@thi.ng/adjacency 2.5.12 → 2.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/api.js +0 -1
- package/bfs.js +49 -79
- package/binary.js +93 -103
- package/dfs.js +40 -45
- package/disjoint-set.js +85 -95
- package/floyd-warshall.js +77 -99
- package/list.js +137 -134
- package/mst.js +13 -60
- package/package.json +13 -10
- package/sparse.js +161 -158
- package/utils.js +24 -22
package/sparse.js
CHANGED
|
@@ -1,168 +1,171 @@
|
|
|
1
1
|
import { ensureIndex2 } from "@thi.ng/errors/out-of-bounds";
|
|
2
2
|
import { CSR } from "@thi.ng/sparse/csr";
|
|
3
3
|
import { __into, __invert, __toDot } from "./utils.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
}
|
|
4
|
+
class AdjacencyMatrix extends CSR {
|
|
5
|
+
undirected;
|
|
6
|
+
constructor(n, data, rows, cols, undirected = false) {
|
|
7
|
+
super(n, n, data, rows, cols);
|
|
8
|
+
this.undirected = undirected;
|
|
9
|
+
}
|
|
10
|
+
*edges() {
|
|
11
|
+
const { cols, rows } = this;
|
|
12
|
+
const directed = !this.undirected;
|
|
13
|
+
for (let i = 0; i < this.m; i++) {
|
|
14
|
+
const jj = rows[i + 1];
|
|
15
|
+
for (let j = rows[i]; j < jj; j++) {
|
|
16
|
+
const k = cols[j];
|
|
17
|
+
if (directed || i <= k) {
|
|
18
|
+
yield [i, k];
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
addEdge(from, to) {
|
|
24
|
+
if (!this.at(from, to)) {
|
|
25
|
+
this.setAt(from, to, 1, false);
|
|
26
|
+
this.undirected && this.setAt(to, from, 1, false);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
removeEdge(from, to) {
|
|
32
|
+
if (this.at(from, to)) {
|
|
33
|
+
this.setAt(from, to, 0, false);
|
|
34
|
+
this.undirected && this.setAt(to, from, 0, false);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
hasEdge(from, to) {
|
|
40
|
+
return this.at(from, to) !== 0;
|
|
41
|
+
}
|
|
42
|
+
hasVertex(id) {
|
|
43
|
+
return this.degree(id, "inout") > 0;
|
|
44
|
+
}
|
|
45
|
+
numEdges() {
|
|
46
|
+
const n = this.data.length;
|
|
47
|
+
return this.undirected ? n / 2 : n;
|
|
48
|
+
}
|
|
49
|
+
numVertices() {
|
|
50
|
+
return this.m;
|
|
51
|
+
}
|
|
52
|
+
degree(id, type = "out") {
|
|
53
|
+
let degree = 0;
|
|
54
|
+
ensureIndex2(id, id, this.m, this.n);
|
|
55
|
+
if (this.undirected || type !== "in")
|
|
56
|
+
degree += this.nnzRow(id);
|
|
57
|
+
if (!this.undirected && type !== "out")
|
|
58
|
+
degree += this.nnzCol(id);
|
|
59
|
+
return degree;
|
|
60
|
+
}
|
|
61
|
+
neighbors(id) {
|
|
62
|
+
return this.nzRowCols(id);
|
|
63
|
+
}
|
|
64
|
+
invert() {
|
|
65
|
+
return __invert(
|
|
66
|
+
defAdjMatrix(this.m, void 0, this.undirected),
|
|
67
|
+
this.edges()
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns a diagonal sparse matrix
|
|
72
|
+
* [`CSR`](https://docs.thi.ng/umbrella/sparse/classes/CSR.html) containing
|
|
73
|
+
* information about the degree of each vertex, i.e. the number of edges
|
|
74
|
+
* attached to each vertex.
|
|
75
|
+
*
|
|
76
|
+
* @remarks
|
|
77
|
+
* Reference: https://en.wikipedia.org/wiki/Degree_matrix
|
|
78
|
+
*
|
|
79
|
+
* @param deg - degree type
|
|
80
|
+
*/
|
|
81
|
+
degreeMat(deg = "out") {
|
|
82
|
+
const res = CSR.empty(this.m);
|
|
83
|
+
switch (deg) {
|
|
84
|
+
case "out":
|
|
85
|
+
default:
|
|
86
|
+
for (let i = this.m; i-- > 0; ) {
|
|
87
|
+
res.setAt(i, i, this.nnzRow(i));
|
|
28
88
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.setAt(from, to, 0, false);
|
|
34
|
-
this.undirected && this.setAt(to, from, 0, false);
|
|
35
|
-
return true;
|
|
89
|
+
break;
|
|
90
|
+
case "in":
|
|
91
|
+
for (let i = this.m; i-- > 0; ) {
|
|
92
|
+
res.setAt(i, i, this.nnzCol(i));
|
|
36
93
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
hasVertex(id) {
|
|
43
|
-
return this.degree(id, "inout") > 0;
|
|
44
|
-
}
|
|
45
|
-
numEdges() {
|
|
46
|
-
const n = this.data.length;
|
|
47
|
-
return this.undirected ? n / 2 : n;
|
|
48
|
-
}
|
|
49
|
-
numVertices() {
|
|
50
|
-
return this.m;
|
|
51
|
-
}
|
|
52
|
-
degree(id, type = "out") {
|
|
53
|
-
let degree = 0;
|
|
54
|
-
ensureIndex2(id, id, this.m, this.n);
|
|
55
|
-
if (this.undirected || type !== "in")
|
|
56
|
-
degree += this.nnzRow(id);
|
|
57
|
-
if (!this.undirected && type !== "out")
|
|
58
|
-
degree += this.nnzCol(id);
|
|
59
|
-
return degree;
|
|
60
|
-
}
|
|
61
|
-
neighbors(id) {
|
|
62
|
-
return this.nzRowCols(id);
|
|
63
|
-
}
|
|
64
|
-
invert() {
|
|
65
|
-
return __invert(defAdjMatrix(this.m, undefined, this.undirected), this.edges());
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Returns a diagonal sparse matrix
|
|
69
|
-
* [`CSR`](https://docs.thi.ng/umbrella/sparse/classes/CSR.html) containing
|
|
70
|
-
* information about the degree of each vertex, i.e. the number of edges
|
|
71
|
-
* attached to each vertex.
|
|
72
|
-
*
|
|
73
|
-
* @remarks
|
|
74
|
-
* Reference: https://en.wikipedia.org/wiki/Degree_matrix
|
|
75
|
-
*
|
|
76
|
-
* @param deg - degree type
|
|
77
|
-
*/
|
|
78
|
-
degreeMat(deg = "out") {
|
|
79
|
-
const res = CSR.empty(this.m);
|
|
80
|
-
switch (deg) {
|
|
81
|
-
case "out":
|
|
82
|
-
default:
|
|
83
|
-
for (let i = this.m; i-- > 0;) {
|
|
84
|
-
res.setAt(i, i, this.nnzRow(i));
|
|
85
|
-
}
|
|
86
|
-
break;
|
|
87
|
-
case "in":
|
|
88
|
-
for (let i = this.m; i-- > 0;) {
|
|
89
|
-
res.setAt(i, i, this.nnzCol(i));
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
case "inout":
|
|
93
|
-
for (let i = this.m; i-- > 0;) {
|
|
94
|
-
res.setAt(i, i, this.nnzRow(i) + this.nnzCol(i));
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
94
|
+
break;
|
|
95
|
+
case "inout":
|
|
96
|
+
for (let i = this.m; i-- > 0; ) {
|
|
97
|
+
res.setAt(i, i, this.nnzRow(i) + this.nnzCol(i));
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns this graph's Laplacian matrix: `L = D - A` Where `D` is the
|
|
105
|
+
* degree matrix and `A` this adjacency matrix.
|
|
106
|
+
*
|
|
107
|
+
* @remarks
|
|
108
|
+
* References:
|
|
109
|
+
* - https://en.wikipedia.org/wiki/Laplacian_matrix
|
|
110
|
+
* - https://en.wikipedia.org/wiki/Discrete_Laplace_operator
|
|
111
|
+
*
|
|
112
|
+
* @param deg - degree type for {@link AdjacencyMatrix.degreeMat}
|
|
113
|
+
*/
|
|
114
|
+
laplacianMat(deg) {
|
|
115
|
+
return (deg || this.degreeMat()).sub(this);
|
|
116
|
+
}
|
|
117
|
+
normalizedLaplacian(deg) {
|
|
118
|
+
deg = deg || this.degreeMat();
|
|
119
|
+
const m = this.m;
|
|
120
|
+
const res = CSR.empty(m);
|
|
121
|
+
for (let i = 0; i < m; i++) {
|
|
122
|
+
for (let j = 0; j < m; j++) {
|
|
123
|
+
if (i === j && deg.at(i, i) > 0) {
|
|
124
|
+
res.setAt(i, j, 1);
|
|
125
|
+
} else if (i !== j && this.at(i, j) > 0) {
|
|
126
|
+
res.setAt(
|
|
127
|
+
i,
|
|
128
|
+
j,
|
|
129
|
+
-1 / Math.sqrt(deg.at(i, i) * deg.at(j, j))
|
|
130
|
+
);
|
|
127
131
|
}
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return res;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Computes: `I - nA + n^2 * (D - I)`, where `I` is the identity matrix,
|
|
138
|
+
* `A` the adjacency matrix, `D` the degree matrix, and `n` is a
|
|
139
|
+
* (complex-valued) number.
|
|
140
|
+
*
|
|
141
|
+
* @remarks
|
|
142
|
+
* See {@link AdjacencyMatrix.degreeMat}.
|
|
143
|
+
*
|
|
144
|
+
* @param n - scale factor
|
|
145
|
+
* @param deg - degree matrix
|
|
146
|
+
*/
|
|
147
|
+
deformedLaplacian(n, deg) {
|
|
148
|
+
deg = deg ? deg.copy() : this.degreeMat();
|
|
149
|
+
const I = CSR.identity(this.m);
|
|
150
|
+
return I.copy().sub(this.copy().mulN(n)).add(deg.sub(I).mulN(n * n));
|
|
151
|
+
}
|
|
152
|
+
toDot(ids) {
|
|
153
|
+
return __toDot(this.edges(), this.undirected, ids);
|
|
154
|
+
}
|
|
151
155
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return mat;
|
|
156
|
+
const defAdjMatrix = (n, edges, undirected = false) => {
|
|
157
|
+
const raw = CSR.empty(n);
|
|
158
|
+
const mat = new AdjacencyMatrix(
|
|
159
|
+
n,
|
|
160
|
+
raw.data,
|
|
161
|
+
raw.rows,
|
|
162
|
+
raw.cols,
|
|
163
|
+
undirected
|
|
164
|
+
);
|
|
165
|
+
edges && __into(mat, edges);
|
|
166
|
+
return mat;
|
|
167
|
+
};
|
|
168
|
+
export {
|
|
169
|
+
AdjacencyMatrix,
|
|
170
|
+
defAdjMatrix
|
|
168
171
|
};
|
package/utils.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return res.join("\n");
|
|
1
|
+
const __toDot = (edges, undirected, ids) => {
|
|
2
|
+
const [type, sep] = undirected ? ["graph", "--"] : ["digraph", "->"];
|
|
3
|
+
const res = [`${type} g {`];
|
|
4
|
+
for (let e of edges) {
|
|
5
|
+
res.push(
|
|
6
|
+
ids ? `"${ids[e[0]]}"${sep}"${ids[e[1]]}";` : `"${e[0]}"${sep}"${e[1]}";`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
res.push(`}`);
|
|
10
|
+
return res.join("\n");
|
|
12
11
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
12
|
+
const __into = (graph, edges) => {
|
|
13
|
+
for (let e of edges) {
|
|
14
|
+
graph.addEdge(e[0], e[1]);
|
|
15
|
+
}
|
|
18
16
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const __invert = (graph, edges) => {
|
|
18
|
+
for (let e of edges) {
|
|
19
|
+
graph.addEdge(e[1], e[0]);
|
|
20
|
+
}
|
|
21
|
+
return graph;
|
|
22
|
+
};
|
|
23
|
+
export {
|
|
24
|
+
__into,
|
|
25
|
+
__invert,
|
|
26
|
+
__toDot
|
|
25
27
|
};
|