Skip to content

Commit

Permalink
refactor(sparse): various minor updates & fixes
Browse files Browse the repository at this point in the history
- update AdjacencyMatrix.edges() for undirected graphs
  (only emit one direction per edge)
- update AM.toDot() (graph vs. digraph)
  • Loading branch information
postspectacular committed Feb 15, 2019
1 parent 604fca1 commit 436fadd
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 113 deletions.
48 changes: 28 additions & 20 deletions packages/sparse/src/adjacency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CSR } from "./csr";

export class AdjacencyMatrix extends CSR {

public static newEmpty(n: number, undirected = true) {
static newEmpty(n: number, undirected = true) {
const raw = CSR.empty(n);
return new AdjacencyMatrix(n, raw.data, raw.rows, raw.cols, undirected);
}
Expand All @@ -19,7 +19,7 @@ export class AdjacencyMatrix extends CSR {
* @param edges
* @param undirected
*/
public static fromEdges(n: number, edges: number[][], undirected = true) {
static fromEdges(n: number, edges: number[][], undirected = true) {
const mat = AdjacencyMatrix.newEmpty(n, undirected);
for (let i = edges.length - 1; i >= 0; i--) {
const e = edges[i];
Expand All @@ -28,7 +28,7 @@ export class AdjacencyMatrix extends CSR {
return mat;
}

public static fromGrid2D(w: number, h: number, wrap = true) {
static fromGrid(w: number, h: number, wrap = true) {
const mat = AdjacencyMatrix.newEmpty(w * h, true);
if (wrap) {
for (let x = 0, last = w * (h - 1); x < w; x++) {
Expand Down Expand Up @@ -60,42 +60,46 @@ export class AdjacencyMatrix extends CSR {
return mat;
}

public undirected: boolean;
undirected: boolean;

constructor(n: number, data: number[], rows: number[], cols: number[], undirected = true) {
super(n, n, data, rows, cols);
this.undirected = undirected;
}

public addEdge(to: number, from: number) {
addEdge(to: number, from: number) {
this.setAt(to, from, 1);
this.undirected && this.setAt(from, to, 1);
}

public removeEdge(to: number, from: number) {
removeEdge(to: number, from: number) {
this.setAt(to, from, 0);
this.undirected && this.setAt(from, to, 0);
}

public hasEdge(to: number, from: number) {
hasEdge(to: number, from: number) {
return this.at(to, from) !== 0;
}

public numEdges() {
numEdges() {
return this.data.length;
}

public numVertices() {
numVertices() {
return this.m;
}

public *edges() {
const rows = this.rows,
cols = this.cols;
*edges() {
const rows = this.rows;
const cols = this.cols;
const undirected = this.undirected;
for (let i = 0; i < this.m; i++) {
const jj = rows[i + 1];
for (let j = rows[i]; j < jj; j++) {
yield [i, cols[j]];
const k = cols[j];
if (!undirected || i <= k) {
yield [i, k];
}
}
}
}
Expand All @@ -104,7 +108,7 @@ export class AdjacencyMatrix extends CSR {
*
* @param deg
*/
public degreeMat(deg: DegreeType = DegreeType.OUT) {
degreeMat(deg: DegreeType = DegreeType.OUT) {
const res = CSR.empty(this.m),
m = this.m - 1;
switch (deg) {
Expand Down Expand Up @@ -133,14 +137,15 @@ export class AdjacencyMatrix extends CSR {
* Where `D` is the degree matrix and `A` this adjacency matrix.
*
* https://en.wikipedia.org/wiki/Laplacian_matrix
* https://en.wikipedia.org/wiki/Discrete_Laplace_operator
*
* @param deg degree type for `degreeMat()`
*/
public laplacianMat(deg?: CSR) {
laplacianMat(deg?: CSR) {
return (deg || this.degreeMat()).sub(this);
}

public normalizedLaplacian(deg?: CSR) {
normalizedLaplacian(deg?: CSR) {
deg = deg || this.degreeMat();
const m = this.m,
res = AdjacencyMatrix.newEmpty(m);
Expand All @@ -162,17 +167,20 @@ export class AdjacencyMatrix extends CSR {
* @param n
* @param deg
*/
public deformedLaplacian(n: number, deg?: CSR) {
deformedLaplacian(n: number, deg?: CSR) {
deg = deg || this.degreeMat();
const I = CSR.identity(this.m);
return I.copy().sub(this.copy().mulN(n)).add(deg.copy().sub(I).mulN(n * n));
}

public toDot() {
const res = [`digraph g {`];
toDot() {
const [type, sep] = this.undirected ?
["graph", "--"] :
["digraph", "->"];
const res = [`${type} g {`];
for (let i = 0; i < this.m; i++) {
for (let j of this.nzRowCols(i)) {
res.push(`"${j}"--"${i}";`);
res.push(`"${j}"${sep}"${i}";`);
}
}
res.push(`}`);
Expand Down
10 changes: 5 additions & 5 deletions packages/sparse/src/amatrix.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
export abstract class AMatrix {

public readonly m: number;
public readonly n: number;
readonly m: number;
readonly n: number;

constructor(m: number, n = m) {
this.m = m;
this.n = n;
}

public abstract at(m: number, n: number, safe?: boolean): number;
abstract at(m: number, n: number, safe?: boolean): number;

public abstract setAt(m: number, n: number, v: number, safe?: boolean): this;
abstract setAt(m: number, n: number, v: number, safe?: boolean): this;

public abstract toDense(): ArrayLike<number>[];
abstract toDense(): ArrayLike<number>[];

protected ensureIndex(m: number, n: number) {
if (m < 0 || m >= this.m || n < 0 || n >= this.n) {
Expand Down
26 changes: 13 additions & 13 deletions packages/sparse/src/binary.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export class AdjacencyBitMatrix {

public data: Uint32Array;
public stride: number;
public n: number;
data: Uint32Array;
stride: number;
n: number;

constructor(n: number) {
this.n = n = (n + 31) & ~31;
Expand All @@ -15,7 +15,7 @@ export class AdjacencyBitMatrix {
*
* @param n
*/
public expand(n: number) {
expand(n: number) {
n = (n + 31) & ~31;
const dstride = n >>> 5,
sstride = this.stride,
Expand All @@ -30,16 +30,16 @@ export class AdjacencyBitMatrix {
return this;
}

public get(m: number, n: number) {
get(m: number, n: number) {
return (this.data[(n >>> 5) + m * this.stride] & (0x80000000 >>> (n & 31))) !== 0;
}

public getSym(m: number, n: number) {
getSym(m: number, n: number) {
return ((this.data[(n >>> 5) + m * this.stride] & (0x80000000 >>> (n & 31))) ||
(this.data[(m >>> 5) + n * this.stride] & (0x80000000 >>> (m & 31)))) !== 0;
}

public set(m: number, n: number, v = true) {
set(m: number, n: number, v = true) {
const id = (n >>> 5) + m * this.stride,
mask = 0x80000000 >>> (n & 31);
if (v) {
Expand All @@ -50,7 +50,7 @@ export class AdjacencyBitMatrix {
return this;
}

public setSym(m: number, n: number, v = true) {
setSym(m: number, n: number, v = true) {
const id1 = (n >>> 5) + m * this.stride,
id2 = (m >>> 5) + n * this.stride,
m1 = 0x80000000 >>> (n & 31),
Expand All @@ -65,7 +65,7 @@ export class AdjacencyBitMatrix {
return this;
}

public valence(m: number) {
valence(m: number) {
m *= this.stride;
let res = 0;
for (let i = m + this.stride - 1; i >= m; i--) {
Expand All @@ -75,7 +75,7 @@ export class AdjacencyBitMatrix {
return res;
}

public neighbors(m: number) {
neighbors(m: number) {
m *= this.stride;
let res: number[] = [];
for (let i = this.n - 1, j = m + this.stride - 1; i >= 0; i -= 32, j--) {
Expand All @@ -89,7 +89,7 @@ export class AdjacencyBitMatrix {
return res;
}

public edges() {
edges() {
const res: number[][] = [];
for (let i = this.n - 1; i >= 0; i--) {
for (let n of this.neighbors(i)) {
Expand All @@ -99,7 +99,7 @@ export class AdjacencyBitMatrix {
return res;
}

public edgesSym() {
edgesSym() {
const res: number[][] = [];
for (let i = this.n - 1; i >= 0; i--) {
for (let n of this.neighbors(i)) {
Expand All @@ -109,7 +109,7 @@ export class AdjacencyBitMatrix {
return res;
}

public toString() {
toString() {
const res: string[] = [],
s = this.stride;
for (let i = 0, j = 0; i < this.n; i++ , j += s) {
Expand Down
22 changes: 11 additions & 11 deletions packages/sparse/src/coo.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { partition } from "@thi.ng/iterators/partition";
import { partition } from "@thi.ng/transducers";
import { Triple } from "./api";
import { AMatrix } from "./amatrix";
import { CSR } from "./csr";

export class COO extends AMatrix {

public static fromDense(m: number, n: number, data: ArrayLike<number>) {
static fromDense(m: number, n: number, data: ArrayLike<number>) {
const res = [];
for (let i = 0, k = 0; i < m; i++) {
for (let j = 0; j < n; j++ , k++) {
Expand All @@ -17,11 +17,11 @@ export class COO extends AMatrix {
return new COO(m, n, res);
}

public static identity(m: number) {
static identity(m: number) {
return COO.diag(new Array(m).fill(1));
}

public static diag(vals: ArrayLike<number>) {
static diag(vals: ArrayLike<number>) {
const res = [],
n = vals.length;
for (let i = 0; i < n; i++) {
Expand All @@ -30,18 +30,18 @@ export class COO extends AMatrix {
return new COO(n, n, res);
}

public data: number[];
data: number[];

constructor(m: number, n = m, data?: number[]) {
super(m, n);
this.data = data || [];
}

public triples() {
triples() {
return <IterableIterator<Triple>>partition(3, 3, this.data);
}

public at(m: number, n: number, safe = true) {
at(m: number, n: number, safe = true) {
safe && this.ensureIndex(m, n);
const d = this.data;
for (let i = 0, l = d.length; i < l && d[i] <= m; i += 3) {
Expand All @@ -52,7 +52,7 @@ export class COO extends AMatrix {
return 0;
}

public setAt(m: number, n: number, v: number, safe = true) {
setAt(m: number, n: number, v: number, safe = true) {
safe && this.ensureIndex(m, n);
const d = this.data;
for (let i = 0, l = d.length; i < l; i += 3) {
Expand All @@ -70,7 +70,7 @@ export class COO extends AMatrix {
return this;
}

public mulV(v: number[]) {
mulV(v: number[]) {
const res = new Array(this.m).fill(0),
d = this.data;
for (let i = d.length - 3; i >= 0; i -= 3) {
Expand All @@ -79,7 +79,7 @@ export class COO extends AMatrix {
return res;
}

public toDense() {
toDense() {
const n = this.n,
d = this.data,
res = new Array(this.m * this.n).fill(0);
Expand All @@ -89,7 +89,7 @@ export class COO extends AMatrix {
return res;
}

public toCSR() {
toCSR() {
const d = [],
r = [0],
c = [],
Expand Down
Loading

0 comments on commit 436fadd

Please sign in to comment.