@graphty/layout 1.2.8 → 1.3.2

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.
Files changed (185) hide show
  1. package/README.md +394 -404
  2. package/dist/layout.js +881 -821
  3. package/dist/layout.js.map +1 -1
  4. package/dist/src/algorithms/index.d.ts +2 -2
  5. package/dist/src/algorithms/index.js +2 -2
  6. package/dist/src/algorithms/index.js.map +1 -1
  7. package/dist/src/algorithms/optimization/index.d.ts +4 -4
  8. package/dist/src/algorithms/optimization/index.js +3 -3
  9. package/dist/src/algorithms/optimization/index.js.map +1 -1
  10. package/dist/src/algorithms/optimization/kamada-kawai-solver.d.ts +2 -5
  11. package/dist/src/algorithms/optimization/kamada-kawai-solver.js +6 -9
  12. package/dist/src/algorithms/optimization/kamada-kawai-solver.js.map +1 -1
  13. package/dist/src/algorithms/optimization/lbfgs.d.ts +0 -1
  14. package/dist/src/algorithms/optimization/lbfgs.js +3 -5
  15. package/dist/src/algorithms/optimization/lbfgs.js.map +1 -1
  16. package/dist/src/algorithms/optimization/line-search.d.ts +0 -1
  17. package/dist/src/algorithms/optimization/line-search.js +0 -1
  18. package/dist/src/algorithms/optimization/line-search.js.map +1 -1
  19. package/dist/src/algorithms/optimization/types.d.ts +1 -1
  20. package/dist/src/algorithms/planarity/check.d.ts +3 -3
  21. package/dist/src/algorithms/planarity/check.js +7 -7
  22. package/dist/src/algorithms/planarity/check.js.map +1 -1
  23. package/dist/src/algorithms/planarity/embedding.d.ts +3 -5
  24. package/dist/src/algorithms/planarity/embedding.js +20 -16
  25. package/dist/src/algorithms/planarity/embedding.js.map +1 -1
  26. package/dist/src/algorithms/planarity/index.d.ts +4 -4
  27. package/dist/src/algorithms/planarity/index.js +4 -4
  28. package/dist/src/algorithms/planarity/index.js.map +1 -1
  29. package/dist/src/algorithms/planarity/lr-test.d.ts +3 -3
  30. package/dist/src/algorithms/planarity/lr-test.js +5 -5
  31. package/dist/src/algorithms/planarity/lr-test.js.map +1 -1
  32. package/dist/src/algorithms/planarity/special-graphs.d.ts +1 -4
  33. package/dist/src/algorithms/planarity/special-graphs.js +18 -15
  34. package/dist/src/algorithms/planarity/special-graphs.js.map +1 -1
  35. package/dist/src/generators/basic.d.ts +1 -1
  36. package/dist/src/generators/basic.js +4 -4
  37. package/dist/src/generators/basic.js.map +1 -1
  38. package/dist/src/generators/bipartite.d.ts +1 -1
  39. package/dist/src/generators/bipartite.js +2 -2
  40. package/dist/src/generators/bipartite.js.map +1 -1
  41. package/dist/src/generators/grid.d.ts +1 -1
  42. package/dist/src/generators/grid.js +1 -1
  43. package/dist/src/generators/grid.js.map +1 -1
  44. package/dist/src/generators/index.d.ts +5 -5
  45. package/dist/src/generators/index.js +5 -5
  46. package/dist/src/generators/index.js.map +1 -1
  47. package/dist/src/generators/random.d.ts +1 -1
  48. package/dist/src/generators/random.js +2 -2
  49. package/dist/src/generators/random.js.map +1 -1
  50. package/dist/src/generators/scale-free.d.ts +1 -1
  51. package/dist/src/generators/scale-free.js +4 -4
  52. package/dist/src/generators/scale-free.js.map +1 -1
  53. package/dist/src/index.d.ts +4 -4
  54. package/dist/src/index.js +4 -4
  55. package/dist/src/layouts/basic/index.d.ts +1 -1
  56. package/dist/src/layouts/basic/index.js +1 -1
  57. package/dist/src/layouts/basic/random.d.ts +1 -2
  58. package/dist/src/layouts/basic/random.js +3 -4
  59. package/dist/src/layouts/basic/random.js.map +1 -1
  60. package/dist/src/layouts/force-directed/arf.d.ts +1 -2
  61. package/dist/src/layouts/force-directed/arf.js +13 -8
  62. package/dist/src/layouts/force-directed/arf.js.map +1 -1
  63. package/dist/src/layouts/force-directed/forceatlas2.d.ts +1 -2
  64. package/dist/src/layouts/force-directed/forceatlas2.js +58 -35
  65. package/dist/src/layouts/force-directed/forceatlas2.js.map +1 -1
  66. package/dist/src/layouts/force-directed/fruchterman-reingold.d.ts +11 -12
  67. package/dist/src/layouts/force-directed/fruchterman-reingold.js +17 -17
  68. package/dist/src/layouts/force-directed/fruchterman-reingold.js.map +1 -1
  69. package/dist/src/layouts/force-directed/index.d.ts +5 -5
  70. package/dist/src/layouts/force-directed/index.js +5 -5
  71. package/dist/src/layouts/force-directed/index.js.map +1 -1
  72. package/dist/src/layouts/force-directed/kamada-kawai.d.ts +2 -3
  73. package/dist/src/layouts/force-directed/kamada-kawai.js +12 -10
  74. package/dist/src/layouts/force-directed/kamada-kawai.js.map +1 -1
  75. package/dist/src/layouts/force-directed/spring.d.ts +11 -12
  76. package/dist/src/layouts/force-directed/spring.js +11 -12
  77. package/dist/src/layouts/force-directed/spring.js.map +1 -1
  78. package/dist/src/layouts/geometric/circular.d.ts +1 -2
  79. package/dist/src/layouts/geometric/circular.js +10 -9
  80. package/dist/src/layouts/geometric/circular.js.map +1 -1
  81. package/dist/src/layouts/geometric/index.d.ts +3 -3
  82. package/dist/src/layouts/geometric/index.js +3 -3
  83. package/dist/src/layouts/geometric/shell.d.ts +1 -2
  84. package/dist/src/layouts/geometric/shell.js +5 -5
  85. package/dist/src/layouts/geometric/shell.js.map +1 -1
  86. package/dist/src/layouts/geometric/spiral.d.ts +1 -2
  87. package/dist/src/layouts/geometric/spiral.js +5 -9
  88. package/dist/src/layouts/geometric/spiral.js.map +1 -1
  89. package/dist/src/layouts/hierarchical/bfs.d.ts +2 -3
  90. package/dist/src/layouts/hierarchical/bfs.js +5 -6
  91. package/dist/src/layouts/hierarchical/bfs.js.map +1 -1
  92. package/dist/src/layouts/hierarchical/bipartite.d.ts +2 -3
  93. package/dist/src/layouts/hierarchical/bipartite.js +8 -9
  94. package/dist/src/layouts/hierarchical/bipartite.js.map +1 -1
  95. package/dist/src/layouts/hierarchical/index.d.ts +3 -3
  96. package/dist/src/layouts/hierarchical/index.js +3 -3
  97. package/dist/src/layouts/hierarchical/index.js.map +1 -1
  98. package/dist/src/layouts/hierarchical/multipartite.d.ts +2 -3
  99. package/dist/src/layouts/hierarchical/multipartite.js +7 -8
  100. package/dist/src/layouts/hierarchical/multipartite.js.map +1 -1
  101. package/dist/src/layouts/index.d.ts +5 -5
  102. package/dist/src/layouts/index.js +5 -5
  103. package/dist/src/layouts/index.js.map +1 -1
  104. package/dist/src/layouts/specialized/index.d.ts +2 -2
  105. package/dist/src/layouts/specialized/index.js +2 -2
  106. package/dist/src/layouts/specialized/index.js.map +1 -1
  107. package/dist/src/layouts/specialized/planar.d.ts +3 -3
  108. package/dist/src/layouts/specialized/planar.js +8 -8
  109. package/dist/src/layouts/specialized/planar.js.map +1 -1
  110. package/dist/src/layouts/specialized/spectral.d.ts +1 -2
  111. package/dist/src/layouts/specialized/spectral.js +30 -20
  112. package/dist/src/layouts/specialized/spectral.js.map +1 -1
  113. package/dist/src/types/embedding.d.ts +1 -1
  114. package/dist/src/types/index.d.ts +3 -3
  115. package/dist/src/types/index.js +3 -3
  116. package/dist/src/types/index.js.map +1 -1
  117. package/dist/src/types/layout.d.ts +1 -1
  118. package/dist/src/utils/graph.d.ts +1 -5
  119. package/dist/src/utils/graph.js +4 -6
  120. package/dist/src/utils/graph.js.map +1 -1
  121. package/dist/src/utils/index.d.ts +5 -5
  122. package/dist/src/utils/index.js +5 -5
  123. package/dist/src/utils/index.js.map +1 -1
  124. package/dist/src/utils/numpy.js +22 -16
  125. package/dist/src/utils/numpy.js.map +1 -1
  126. package/dist/src/utils/params.d.ts +1 -2
  127. package/dist/src/utils/params.js +0 -1
  128. package/dist/src/utils/params.js.map +1 -1
  129. package/dist/src/utils/random.d.ts +17 -0
  130. package/dist/src/utils/random.js +18 -1
  131. package/dist/src/utils/random.js.map +1 -1
  132. package/dist/src/utils/rescale.d.ts +1 -3
  133. package/dist/src/utils/rescale.js +12 -10
  134. package/dist/src/utils/rescale.js.map +1 -1
  135. package/dist/vitest.config.js +14 -14
  136. package/dist/vitest.config.js.map +1 -1
  137. package/package.json +29 -24
  138. package/src/algorithms/index.ts +2 -2
  139. package/src/algorithms/optimization/index.ts +4 -8
  140. package/src/algorithms/optimization/kamada-kawai-solver.ts +170 -179
  141. package/src/algorithms/optimization/lbfgs.ts +41 -48
  142. package/src/algorithms/optimization/line-search.ts +27 -28
  143. package/src/algorithms/optimization/types.ts +2 -2
  144. package/src/algorithms/planarity/check.ts +22 -21
  145. package/src/algorithms/planarity/embedding.ts +159 -165
  146. package/src/algorithms/planarity/index.ts +4 -8
  147. package/src/algorithms/planarity/lr-test.ts +46 -45
  148. package/src/algorithms/planarity/special-graphs.ts +73 -83
  149. package/src/generators/basic.ts +57 -57
  150. package/src/generators/bipartite.ts +37 -31
  151. package/src/generators/grid.ts +28 -28
  152. package/src/generators/index.ts +5 -11
  153. package/src/generators/random.ts +26 -25
  154. package/src/generators/scale-free.ts +56 -55
  155. package/src/index.ts +5 -5
  156. package/src/layouts/basic/index.ts +1 -1
  157. package/src/layouts/basic/random.ts +20 -16
  158. package/src/layouts/force-directed/arf.ts +107 -105
  159. package/src/layouts/force-directed/forceatlas2.ts +365 -351
  160. package/src/layouts/force-directed/fruchterman-reingold.ts +133 -134
  161. package/src/layouts/force-directed/index.ts +5 -5
  162. package/src/layouts/force-directed/kamada-kawai.ts +78 -80
  163. package/src/layouts/force-directed/spring.ts +24 -25
  164. package/src/layouts/geometric/circular.ts +63 -57
  165. package/src/layouts/geometric/index.ts +3 -3
  166. package/src/layouts/geometric/shell.ts +58 -53
  167. package/src/layouts/geometric/spiral.ts +60 -64
  168. package/src/layouts/hierarchical/bfs.ts +58 -59
  169. package/src/layouts/hierarchical/bipartite.ts +62 -63
  170. package/src/layouts/hierarchical/index.ts +3 -3
  171. package/src/layouts/hierarchical/multipartite.ts +62 -63
  172. package/src/layouts/index.ts +5 -5
  173. package/src/layouts/specialized/index.ts +2 -2
  174. package/src/layouts/specialized/planar.ts +42 -41
  175. package/src/layouts/specialized/spectral.ts +110 -99
  176. package/src/types/embedding.ts +5 -5
  177. package/src/types/graph.ts +4 -4
  178. package/src/types/index.ts +3 -3
  179. package/src/types/layout.ts +2 -2
  180. package/src/utils/graph.ts +31 -35
  181. package/src/utils/index.ts +5 -5
  182. package/src/utils/numpy.ts +96 -92
  183. package/src/utils/params.ts +14 -11
  184. package/src/utils/random.ts +57 -40
  185. package/src/utils/rescale.ts +169 -174
@@ -2,14 +2,13 @@
2
2
  * Spectral layout algorithm using eigenvectors of the graph Laplacian
3
3
  */
4
4
 
5
- import { Graph, Node, Edge, PositionMap } from '../../types';
6
- import { _processParams } from '../../utils/params';
7
- import { getNodesFromGraph, getEdgesFromGraph } from '../../utils/graph';
8
- import { rescaleLayout } from '../../utils/rescale';
5
+ import { Edge, Graph, Node, PositionMap } from "../../types";
6
+ import { getEdgesFromGraph,getNodesFromGraph } from "../../utils/graph";
7
+ import { _processParams } from "../../utils/params";
8
+ import { rescaleLayout } from "../../utils/rescale";
9
9
 
10
10
  /**
11
11
  * Position nodes in a spectral layout using eigenvectors of the graph Laplacian.
12
- *
13
12
  * @param G - Graph
14
13
  * @param scale - Scale factor for positions
15
14
  * @param center - Coordinate pair around which to center the layout
@@ -17,112 +16,124 @@ import { rescaleLayout } from '../../utils/rescale';
17
16
  * @returns Positions dictionary keyed by node
18
17
  */
19
18
  export function spectralLayout(
20
- G: Graph,
21
- scale: number = 1,
22
- center: number[] | null = null,
23
- dim: number = 2
19
+ G: Graph,
20
+ scale: number = 1,
21
+ center: number[] | null = null,
22
+ dim: number = 2,
24
23
  ): PositionMap {
25
- const processed = _processParams(G, center, dim);
26
- const graph = processed.G;
27
- center = processed.center;
28
-
29
- const nodes = getNodesFromGraph(graph);
30
-
31
- if (nodes.length <= 2) {
32
- if (nodes.length === 0) {
33
- return {};
34
- } else if (nodes.length === 1) {
35
- return { [nodes[0]]: center };
36
- } else {
37
- return {
38
- [nodes[0]]: center.map(v => v - scale),
39
- [nodes[1]]: center.map(v => v + scale)
40
- };
24
+ const processed = _processParams(G, center, dim);
25
+ const graph = processed.G;
26
+ center = processed.center;
27
+
28
+ const nodes = getNodesFromGraph(graph);
29
+
30
+ if (nodes.length <= 2) {
31
+ if (nodes.length === 0) {
32
+ return {};
33
+ } else if (nodes.length === 1) {
34
+ return { [nodes[0]]: center };
35
+ }
36
+ return {
37
+ [nodes[0]]: center.map((v) => v - scale),
38
+ [nodes[1]]: center.map((v) => v + scale),
39
+ };
40
+
41
41
  }
42
- }
43
-
44
- // Create adjacency matrix
45
- const N = nodes.length;
46
- const nodeIndices: Record<Node, number> = {};
47
- nodes.forEach((node: Node, i: number) => { nodeIndices[node] = i; });
48
-
49
- const A = Array(N).fill(0).map(() => Array(N).fill(0));
50
- const edges = getEdgesFromGraph(graph);
51
-
52
- for (const [source, target] of edges) {
53
- const i = nodeIndices[source];
54
- const j = nodeIndices[target];
55
- A[i][j] = 1;
56
- A[j][i] = 1; // Make symmetric for undirected graphs
57
- }
58
-
59
- // Create Laplacian matrix: L = D - A where D is degree matrix
60
- const L = Array(N).fill(0).map(() => Array(N).fill(0));
61
- for (let i = 0; i < N; i++) {
62
- // Compute degree (sum of row)
63
- L[i][i] = A[i].reduce((sum, val) => sum + val, 0);
64
- for (let j = 0; j < N; j++) {
65
- L[i][j] -= A[i][j];
66
- }
67
- }
68
-
69
- // Compute eigenvectors using power iteration method
70
- // We need the smallest non-zero eigenvectors of L
71
- const eigenvectors: number[][] = [];
72
-
73
- // For each dimension, find an eigenvector
74
- for (let d = 0; d < dim; d++) {
75
- let vector = Array(N).fill(0).map(() => Math.random() - 0.5);
76
42
 
77
- // Orthogonalize against previous eigenvectors
78
- for (const ev of eigenvectors) {
79
- const dot = vector.reduce((acc, val, idx) => acc + val * ev[idx], 0);
80
- vector = vector.map((val, idx) => val - dot * ev[idx]);
43
+ // Create adjacency matrix
44
+ const N = nodes.length;
45
+ const nodeIndices: Record<Node, number> = {};
46
+ nodes.forEach((node: Node, i: number) => {
47
+ nodeIndices[node] = i;
48
+ });
49
+
50
+ const A = Array(N)
51
+ .fill(0)
52
+ .map(() => Array(N).fill(0));
53
+ const edges = getEdgesFromGraph(graph);
54
+
55
+ for (const [source, target] of edges) {
56
+ const i = nodeIndices[source];
57
+ const j = nodeIndices[target];
58
+ A[i][j] = 1;
59
+ A[j][i] = 1; // Make symmetric for undirected graphs
81
60
  }
82
61
 
83
- // Normalize
84
- const norm = Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0));
85
- vector = vector.map(val => val / norm);
86
-
87
- // Apply shifted inverse iteration to find smallest non-zero eigenvector
88
- // This is a simplification of the actual algorithm
89
- for (let iter = 0; iter < 100; iter++) {
90
- // Apply Laplacian
91
- const newVec = Array(N).fill(0);
92
- for (let i = 0; i < N; i++) {
62
+ // Create Laplacian matrix: L = D - A where D is degree matrix
63
+ const L = Array(N)
64
+ .fill(0)
65
+ .map(() => Array(N).fill(0));
66
+ for (let i = 0; i < N; i++) {
67
+ // Compute degree (sum of row)
68
+ L[i][i] = A[i].reduce((sum, val) => sum + val, 0);
93
69
  for (let j = 0; j < N; j++) {
94
- newVec[i] += L[i][j] * vector[j];
70
+ L[i][j] -= A[i][j];
95
71
  }
96
- }
72
+ }
73
+
74
+ // Compute eigenvectors using power iteration method
75
+ // We need the smallest non-zero eigenvectors of L
76
+ const eigenvectors: number[][] = [];
97
77
 
98
- // Orthogonalize against the constant vector (eigenvector with eigenvalue 0)
99
- const mean = newVec.reduce((acc, val) => acc + val, 0) / N;
100
- newVec.forEach((val, idx, arr) => { arr[idx] = val - mean; });
78
+ // For each dimension, find an eigenvector
79
+ for (let d = 0; d < dim; d++) {
80
+ let vector = Array(N)
81
+ .fill(0)
82
+ .map(() => Math.random() - 0.5);
83
+
84
+ // Orthogonalize against previous eigenvectors
85
+ for (const ev of eigenvectors) {
86
+ const dot = vector.reduce((acc, val, idx) => acc + val * ev[idx], 0);
87
+ vector = vector.map((val, idx) => val - dot * ev[idx]);
88
+ }
101
89
 
102
- // Normalize
103
- const newNorm = Math.sqrt(newVec.reduce((acc, val) => acc + val * val, 0));
104
- if (newNorm < 1e-10) continue; // Skip if vector is close to zero
90
+ // Normalize
91
+ const norm = Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0));
92
+ vector = vector.map((val) => val / norm);
93
+
94
+ // Apply shifted inverse iteration to find smallest non-zero eigenvector
95
+ // This is a simplification of the actual algorithm
96
+ for (let iter = 0; iter < 100; iter++) {
97
+ // Apply Laplacian
98
+ const newVec = Array(N).fill(0);
99
+ for (let i = 0; i < N; i++) {
100
+ for (let j = 0; j < N; j++) {
101
+ newVec[i] += L[i][j] * vector[j];
102
+ }
103
+ }
104
+
105
+ // Orthogonalize against the constant vector (eigenvector with eigenvalue 0)
106
+ const mean = newVec.reduce((acc, val) => acc + val, 0) / N;
107
+ newVec.forEach((val, idx, arr) => {
108
+ arr[idx] = val - mean;
109
+ });
110
+
111
+ // Normalize
112
+ const newNorm = Math.sqrt(newVec.reduce((acc, val) => acc + val * val, 0));
113
+ if (newNorm < 1e-10) {continue;} // Skip if vector is close to zero
114
+
115
+ vector = newVec.map((val) => val / newNorm);
116
+ }
105
117
 
106
- vector = newVec.map(val => val / newNorm);
118
+ eigenvectors.push(vector);
107
119
  }
108
120
 
109
- eigenvectors.push(vector);
110
- }
111
-
112
- // Create position array from eigenvectors
113
- const positions: number[][] = Array(N).fill(0).map(() => Array(dim).fill(0));
114
- for (let i = 0; i < N; i++) {
115
- for (let d = 0; d < dim; d++) {
116
- positions[i][d] = eigenvectors[d][i];
121
+ // Create position array from eigenvectors
122
+ const positions: number[][] = Array(N)
123
+ .fill(0)
124
+ .map(() => Array(dim).fill(0));
125
+ for (let i = 0; i < N; i++) {
126
+ for (let d = 0; d < dim; d++) {
127
+ positions[i][d] = eigenvectors[d][i];
128
+ }
117
129
  }
118
- }
119
130
 
120
- // Rescale and create position dictionary
121
- const scaledPositions = rescaleLayout(positions as any, scale);
122
- const pos: PositionMap = {};
123
- nodes.forEach((node: Node, i: number) => {
124
- pos[node] = (scaledPositions as number[][])[i].map((val: number, j: number) => val + center[j]);
125
- });
131
+ // Rescale and create position dictionary
132
+ const scaledPositions = rescaleLayout(positions as any, scale);
133
+ const pos: PositionMap = {};
134
+ nodes.forEach((node: Node, i: number) => {
135
+ pos[node] = (scaledPositions as number[][])[i].map((val: number, j: number) => val + center[j]);
136
+ });
126
137
 
127
- return pos;
128
- }
138
+ return pos;
139
+ }
@@ -2,10 +2,10 @@
2
2
  * Embedding type for planar layout algorithms
3
3
  */
4
4
 
5
- import { Node, Position } from './index';
5
+ import { Node, Position } from "./index";
6
6
 
7
7
  export interface Embedding {
8
- nodeOrder: Node[];
9
- faceList: Node[][];
10
- nodePositions: Record<Node, Position>;
11
- }
8
+ nodeOrder: Node[];
9
+ faceList: Node[][];
10
+ nodePositions: Record<Node, Position>;
11
+ }
@@ -7,7 +7,7 @@ export type Node = string | number;
7
7
  export type Edge = [Node, Node];
8
8
 
9
9
  export type Graph = {
10
- nodes: () => Node[];
11
- edges: () => Edge[];
12
- getEdgeData?: (source: Node, target: Node, attr: string) => any;
13
- };
10
+ nodes: () => Node[];
11
+ edges: () => Edge[];
12
+ getEdgeData?: (source: Node, target: Node, attr: string) => any;
13
+ };
@@ -2,6 +2,6 @@
2
2
  * Re-export all type definitions
3
3
  */
4
4
 
5
- export * from './graph';
6
- export * from './layout';
7
- export * from './embedding';
5
+ export * from "./embedding";
6
+ export * from "./graph";
7
+ export * from "./layout";
@@ -2,8 +2,8 @@
2
2
  * Layout-specific type definitions
3
3
  */
4
4
 
5
- import { Node } from './graph';
5
+ import { Node } from "./graph";
6
6
 
7
7
  export type Position = number[];
8
8
 
9
- export type PositionMap = Record<Node, Position>;
9
+ export type PositionMap = Record<Node, Position>;
@@ -2,76 +2,72 @@
2
2
  * Graph utility functions
3
3
  */
4
4
 
5
- import { Graph, Node, Edge } from '../types';
5
+ import { Edge,Graph, Node } from "../types";
6
6
 
7
7
  /**
8
8
  * Extract nodes from a graph object
9
- *
10
9
  * @param G - Graph or list of nodes
11
10
  * @returns Array of nodes
12
11
  */
13
12
  export function getNodesFromGraph(G: Graph | Node[]): Node[] {
14
- if (Array.isArray(G)) {
15
- return G;
16
- }
17
- return G.nodes();
13
+ if (Array.isArray(G)) {
14
+ return G;
15
+ }
16
+ return G.nodes();
18
17
  }
19
18
 
20
19
  /**
21
20
  * Extract edges from a graph object
22
- *
23
21
  * @param G - Graph or list of nodes
24
22
  * @returns Array of edges
25
23
  */
26
24
  export function getEdgesFromGraph(G: Graph | Node[]): Edge[] {
27
- if (Array.isArray(G)) {
28
- return [];
29
- }
30
- return G.edges();
25
+ if (Array.isArray(G)) {
26
+ return [];
27
+ }
28
+ return G.edges();
31
29
  }
32
30
 
33
31
  /**
34
32
  * Get the degree of a node in the graph
35
- *
36
33
  * @param graph - Graph object
37
34
  * @param node - Node to get degree for
38
35
  * @returns Degree of the node
39
36
  */
40
37
  export function getNodeDegree(graph: Graph, node: Node): number {
41
- if (!graph.edges) return 0;
42
-
43
- const edges = graph.edges();
44
- let degree = 0;
45
-
46
- for (const [source, target] of edges) {
47
- if (source === node || target === node) {
48
- degree++;
38
+ if (!graph.edges) {return 0;}
39
+
40
+ const edges = graph.edges();
41
+ let degree = 0;
42
+
43
+ for (const [source, target] of edges) {
44
+ if (source === node || target === node) {
45
+ degree++;
46
+ }
49
47
  }
50
- }
51
-
52
- return degree;
48
+
49
+ return degree;
53
50
  }
54
51
 
55
52
  /**
56
53
  * Get the neighbors of a node in the graph
57
- *
58
54
  * @param graph - Graph object
59
55
  * @param node - Node to get neighbors for
60
56
  * @returns Array of neighbor nodes
61
57
  */
62
58
  export function getNeighbors(graph: Graph, node: Node): Node[] {
63
- if (!graph.edges) return [];
59
+ if (!graph.edges) {return [];}
64
60
 
65
- const neighbors = new Set<Node>();
66
- const edges = graph.edges();
61
+ const neighbors = new Set<Node>();
62
+ const edges = graph.edges();
67
63
 
68
- for (const [source, target] of edges) {
69
- if (source === node) {
70
- neighbors.add(target);
71
- } else if (target === node) {
72
- neighbors.add(source);
64
+ for (const [source, target] of edges) {
65
+ if (source === node) {
66
+ neighbors.add(target);
67
+ } else if (target === node) {
68
+ neighbors.add(source);
69
+ }
73
70
  }
74
- }
75
71
 
76
- return Array.from(neighbors);
77
- }
72
+ return Array.from(neighbors);
73
+ }
@@ -2,8 +2,8 @@
2
2
  * Re-export all utilities
3
3
  */
4
4
 
5
- export * from './numpy';
6
- export * from './random';
7
- export * from './graph';
8
- export * from './params';
9
- export * from './rescale';
5
+ export * from "./graph";
6
+ export * from "./numpy";
7
+ export * from "./params";
8
+ export * from "./random";
9
+ export * from "./rescale";
@@ -4,108 +4,112 @@
4
4
  */
5
5
 
6
6
  export const np = {
7
- zeros: function (shape: number | number[]): number | number[] | number[][] | any[] {
8
- if (typeof shape === 'number') {
9
- return Array(shape).fill(0);
10
- }
11
- if (shape.length === 1) {
12
- return Array(shape[0]).fill(0);
13
- }
14
- return Array(shape[0]).fill(0).map(() => this.zeros(shape.slice(1)));
15
- },
7
+ zeros: function (shape: number | number[]): number | number[] | number[][] | any[] {
8
+ if (typeof shape === "number") {
9
+ return Array(shape).fill(0);
10
+ }
11
+ if (shape.length === 1) {
12
+ return Array(shape[0]).fill(0);
13
+ }
14
+ return Array(shape[0])
15
+ .fill(0)
16
+ .map(() => this.zeros(shape.slice(1)));
17
+ },
16
18
 
17
- ones: function (shape: number | number[]): number | any[] {
18
- if (typeof shape === 'number') {
19
- return Array(shape).fill(1);
20
- }
21
- if (shape.length === 1) {
22
- return Array(shape[0]).fill(1);
23
- }
24
- return Array(shape[0]).fill(1).map(() => this.ones(shape.slice(1)));
25
- },
19
+ ones: function (shape: number | number[]): number | any[] {
20
+ if (typeof shape === "number") {
21
+ return Array(shape).fill(1);
22
+ }
23
+ if (shape.length === 1) {
24
+ return Array(shape[0]).fill(1);
25
+ }
26
+ return Array(shape[0])
27
+ .fill(1)
28
+ .map(() => this.ones(shape.slice(1)));
29
+ },
26
30
 
27
- linspace: function (start: number, stop: number, num: number): number[] {
28
- if (num === 1) {
29
- return [start];
30
- }
31
- const step = (stop - start) / (num - 1);
32
- return Array.from({ length: num }, (_, i) => start + i * step);
33
- },
31
+ linspace: function (start: number, stop: number, num: number): number[] {
32
+ if (num === 1) {
33
+ return [start];
34
+ }
35
+ const step = (stop - start) / (num - 1);
36
+ return Array.from({ length: num }, (_, i) => start + i * step);
37
+ },
34
38
 
35
- array: function (arr: any): any[] {
36
- return Array.isArray(arr) ? [...arr] : [arr];
37
- },
39
+ array: function (arr: any): any[] {
40
+ return Array.isArray(arr) ? [...arr] : [arr];
41
+ },
38
42
 
39
- repeat: function (a: any, repeats: number): any[] {
40
- const result: any[] = [];
41
- for (let i = 0; i < repeats; i++) {
42
- result.push(...np.array(a));
43
- }
44
- return result;
45
- },
43
+ repeat: function (a: any, repeats: number): any[] {
44
+ const result: any[] = [];
45
+ for (let i = 0; i < repeats; i++) {
46
+ result.push(...np.array(a));
47
+ }
48
+ return result;
49
+ },
46
50
 
47
- mean: function (arr: number[] | number[][], axis: number | null = null): number | number[] {
48
- if (axis === null) {
49
- const flatArr = Array.isArray(arr[0])
50
- ? (arr as number[][]).flat(Infinity) as number[]
51
- : arr as number[];
52
- const sum = flatArr.reduce((a, b) => a + b, 0);
53
- return sum / flatArr.length;
54
- }
51
+ mean: function (arr: number[] | number[][], axis: number | null = null): number | number[] {
52
+ if (axis === null) {
53
+ const flatArr = Array.isArray(arr[0])
54
+ ? ((arr as number[][]).flat(Infinity) as number[])
55
+ : (arr as number[]);
56
+ const sum = flatArr.reduce((a, b) => a + b, 0);
57
+ return sum / flatArr.length;
58
+ }
55
59
 
56
- if (axis === 0) {
57
- const result: number[] = [];
58
- const matrix = arr as number[][];
59
- for (let i = 0; i < matrix[0].length; i++) {
60
- let sum = 0;
61
- for (let j = 0; j < matrix.length; j++) {
62
- sum += matrix[j][i];
60
+ if (axis === 0) {
61
+ const result: number[] = [];
62
+ const matrix = arr as number[][];
63
+ for (let i = 0; i < matrix[0].length; i++) {
64
+ let sum = 0;
65
+ for (let j = 0; j < matrix.length; j++) {
66
+ sum += matrix[j][i];
67
+ }
68
+ result.push(sum / matrix.length);
69
+ }
70
+ return result;
63
71
  }
64
- result.push(sum / matrix.length);
65
- }
66
- return result;
67
- }
68
72
 
69
- return (arr as number[][]).map(row => np.mean(row) as number);
70
- },
73
+ return (arr as number[][]).map((row) => np.mean(row) as number);
74
+ },
71
75
 
72
- add: function (a: number | number[], b: number | number[]): number | number[] {
73
- if (!Array.isArray(a) && !Array.isArray(b)) {
74
- return a + b;
75
- }
76
- if (!Array.isArray(a)) {
77
- return (b as number[]).map(val => a + val);
78
- }
79
- if (!Array.isArray(b)) {
80
- return (a as number[]).map(val => val + b);
81
- }
82
- return (a as number[]).map((val, i) => val + (b as number[])[i]);
83
- },
76
+ add: function (a: number | number[], b: number | number[]): number | number[] {
77
+ if (!Array.isArray(a) && !Array.isArray(b)) {
78
+ return a + b;
79
+ }
80
+ if (!Array.isArray(a)) {
81
+ return (b as number[]).map((val) => a + val);
82
+ }
83
+ if (!Array.isArray(b)) {
84
+ return (a).map((val) => val + b);
85
+ }
86
+ return (a).map((val, i) => val + (b)[i]);
87
+ },
84
88
 
85
- subtract: function (a: number | number[], b: number | number[]): number | number[] {
86
- if (!Array.isArray(a) && !Array.isArray(b)) {
87
- return a - b;
88
- }
89
- if (!Array.isArray(a)) {
90
- return (b as number[]).map(val => a - val);
91
- }
92
- if (!Array.isArray(b)) {
93
- return (a as number[]).map(val => val - b);
94
- }
95
- return (a as number[]).map((val, i) => val - (b as number[])[i]);
96
- },
89
+ subtract: function (a: number | number[], b: number | number[]): number | number[] {
90
+ if (!Array.isArray(a) && !Array.isArray(b)) {
91
+ return a - b;
92
+ }
93
+ if (!Array.isArray(a)) {
94
+ return (b as number[]).map((val) => a - val);
95
+ }
96
+ if (!Array.isArray(b)) {
97
+ return (a).map((val) => val - b);
98
+ }
99
+ return (a).map((val, i) => val - (b)[i]);
100
+ },
97
101
 
98
- max: function (arr: number | number[]): number {
99
- if (!Array.isArray(arr)) return arr;
100
- return Math.max(...(arr as number[]).flat(Infinity) as number[]);
101
- },
102
+ max: function (arr: number | number[]): number {
103
+ if (!Array.isArray(arr)) {return arr;}
104
+ return Math.max(...((arr).flat(Infinity)));
105
+ },
102
106
 
103
- min: function (arr: number | number[]): number {
104
- if (!Array.isArray(arr)) return arr;
105
- return Math.min(...(arr as number[]).flat(Infinity) as number[]);
106
- },
107
+ min: function (arr: number | number[]): number {
108
+ if (!Array.isArray(arr)) {return arr;}
109
+ return Math.min(...((arr).flat(Infinity)));
110
+ },
107
111
 
108
- norm: function (arr: number[]): number {
109
- return Math.sqrt(arr.reduce((sum, val) => sum + val * val, 0));
110
- }
111
- };
112
+ norm: function (arr: number[]): number {
113
+ return Math.sqrt(arr.reduce((sum, val) => sum + val * val, 0));
114
+ },
115
+ };
@@ -2,25 +2,28 @@
2
2
  * Parameter processing utilities
3
3
  */
4
4
 
5
- import { Graph, Node } from '../types';
5
+ import { Graph, Node } from "../types";
6
6
 
7
7
  /**
8
8
  * Process and validate layout parameters
9
9
  * Helper function similar to _process_params in Python version
10
- *
11
10
  * @param G - Graph object or array of nodes
12
11
  * @param center - Center coordinates or null
13
12
  * @param dim - Dimension of layout
14
13
  * @returns Processed parameters
15
14
  */
16
- export function _processParams(G: Graph | Node[], center: number[] | null, dim: number): { G: Graph | Node[]; center: number[] } {
17
- if (!center) {
18
- center = Array(dim).fill(0);
19
- }
15
+ export function _processParams(
16
+ G: Graph | Node[],
17
+ center: number[] | null,
18
+ dim: number,
19
+ ): { G: Graph | Node[]; center: number[] } {
20
+ if (!center) {
21
+ center = Array(dim).fill(0);
22
+ }
20
23
 
21
- if (center.length !== dim) {
22
- throw new Error("length of center coordinates must match dimension of layout");
23
- }
24
+ if (center.length !== dim) {
25
+ throw new Error("length of center coordinates must match dimension of layout");
26
+ }
24
27
 
25
- return { G, center };
26
- }
28
+ return { G, center };
29
+ }