@graphty/algorithms 1.2.0 → 1.4.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.
- package/README.md +375 -276
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11402 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +14 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +144 -169
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +35 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +70 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.d.ts +7 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +12 -9
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +57 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +304 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +106 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +320 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +11 -4
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/hits.d.ts +10 -3
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/hits.js +11 -4
- package/dist/src/algorithms/centrality/hits.js.map +1 -1
- package/dist/src/algorithms/centrality/index.d.ts +3 -1
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +2 -1
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +10 -3
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/katz.js +13 -8
- package/dist/src/algorithms/centrality/katz.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +31 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +61 -1
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +67 -57
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/index.d.ts +2 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -1
- package/dist/src/algorithms/community/index.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +11 -4
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +60 -38
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -3
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +70 -44
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +149 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +338 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts +2 -3
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +35 -81
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +55 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +108 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/components/connected.d.ts +23 -0
- package/dist/src/algorithms/components/connected.d.ts.map +1 -1
- package/dist/src/algorithms/components/connected.js +29 -3
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +18 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/matching/index.d.ts.map +1 -1
- package/dist/src/algorithms/matching/index.js.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
- package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.js +36 -2
- package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
- package/dist/src/algorithms/mst/index.d.ts.map +1 -1
- package/dist/src/algorithms/mst/index.js.map +1 -1
- package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
- package/dist/src/algorithms/mst/kruskal.js +17 -3
- package/dist/src/algorithms/mst/kruskal.js.map +1 -1
- package/dist/src/algorithms/mst/prim.d.ts +9 -0
- package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
- package/dist/src/algorithms/mst/prim.js +9 -0
- package/dist/src/algorithms/mst/prim.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +11 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +44 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +195 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +20 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +30 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
- package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/index.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +42 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +370 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +77 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +402 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +5 -182
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +48 -0
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/index.js.map +1 -1
- package/dist/src/benchmark-all-algorithms.d.ts +25 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +491 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +23 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +226 -224
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts +4 -2
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js +2 -2
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +17 -19
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +68 -30
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/mcl.d.ts +6 -0
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +34 -3
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +11 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +99 -47
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.d.ts +45 -0
- package/dist/src/core/graph.d.ts.map +1 -1
- package/dist/src/core/graph.js +49 -5
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/data-structures/index.d.ts.map +1 -1
- package/dist/src/data-structures/index.js.map +1 -1
- package/dist/src/data-structures/priority-queue.d.ts +18 -1
- package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
- package/dist/src/data-structures/priority-queue.js +26 -5
- package/dist/src/data-structures/priority-queue.js.map +1 -1
- package/dist/src/data-structures/union-find.d.ts +21 -0
- package/dist/src/data-structures/union-find.d.ts.map +1 -1
- package/dist/src/data-structures/union-find.js +21 -0
- package/dist/src/data-structures/union-find.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +20 -12
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +170 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -8
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +34 -12
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +47 -30
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +31 -14
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/link-prediction/index.d.ts.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +193 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +342 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +149 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +404 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +95 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +242 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +111 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +194 -0
- package/dist/src/optimized/graph-adapter.js.map +1 -0
- package/dist/src/optimized/index.d.ts +14 -0
- package/dist/src/optimized/index.d.ts.map +1 -0
- package/dist/src/optimized/index.js +30 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/pathfinding/astar.d.ts +25 -9
- package/dist/src/pathfinding/astar.d.ts.map +1 -1
- package/dist/src/pathfinding/astar.js +25 -10
- package/dist/src/pathfinding/astar.js.map +1 -1
- package/dist/src/pathfinding/utils.d.ts +15 -6
- package/dist/src/pathfinding/utils.d.ts.map +1 -1
- package/dist/src/pathfinding/utils.js +19 -7
- package/dist/src/pathfinding/utils.js.map +1 -1
- package/dist/src/research/grsbm.d.ts +0 -1
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +28 -23
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/index.d.ts.map +1 -1
- package/dist/src/research/index.js.map +1 -1
- package/dist/src/research/sync.d.ts +0 -1
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +31 -36
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +2 -1
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +39 -7
- package/dist/src/research/terahac.js.map +1 -1
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/algorithm-utilities.d.ts +2 -0
- package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
- package/dist/src/utils/algorithm-utilities.js +2 -0
- package/dist/src/utils/algorithm-utilities.js.map +1 -0
- package/dist/src/utils/graph-converters.d.ts +110 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +227 -0
- package/dist/src/utils/graph-converters.js.map +1 -0
- package/dist/src/utils/graph-utilities.d.ts +62 -0
- package/dist/src/utils/graph-utilities.d.ts.map +1 -0
- package/dist/src/utils/graph-utilities.js +148 -0
- package/dist/src/utils/graph-utilities.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/math-utilities.d.ts +63 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +132 -0
- package/dist/src/utils/math-utilities.js.map +1 -0
- package/dist/src/utils/matrix-utilities.d.ts +2 -0
- package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
- package/dist/src/utils/matrix-utilities.js +2 -0
- package/dist/src/utils/matrix-utilities.js.map +1 -0
- package/dist/src/utils/optimization-helpers.d.ts +42 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +59 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/dist/src/utils/priorityQueue.d.ts +24 -0
- package/dist/src/utils/priorityQueue.d.ts.map +1 -1
- package/dist/src/utils/priorityQueue.js +34 -4
- package/dist/src/utils/priorityQueue.js.map +1 -1
- package/package.json +58 -39
- package/src/algorithms/centrality/betweenness.ts +185 -200
- package/src/algorithms/centrality/closeness.ts +93 -194
- package/src/algorithms/centrality/degree.ts +18 -22
- package/src/algorithms/centrality/delta-pagerank-simple.ts +374 -0
- package/src/algorithms/centrality/delta-pagerank.ts +458 -0
- package/src/algorithms/centrality/eigenvector.ts +14 -15
- package/src/algorithms/centrality/hits.ts +17 -17
- package/src/algorithms/centrality/index.ts +20 -13
- package/src/algorithms/centrality/katz.ts +17 -25
- package/src/algorithms/centrality/pagerank.ts +91 -16
- package/src/algorithms/community/girvan-newman.ts +90 -86
- package/src/algorithms/community/index.ts +6 -5
- package/src/algorithms/community/label-propagation.ts +69 -48
- package/src/algorithms/community/leiden.ts +88 -65
- package/src/algorithms/community/louvain-optimized.ts +474 -0
- package/src/algorithms/community/louvain.ts +52 -122
- package/src/algorithms/community/modularity-utils.ts +134 -0
- package/src/algorithms/components/connected.ts +40 -17
- package/src/algorithms/matching/bipartite.ts +24 -53
- package/src/algorithms/matching/index.ts +4 -4
- package/src/algorithms/matching/isomorphism.ts +53 -23
- package/src/algorithms/mst/index.ts +3 -4
- package/src/algorithms/mst/kruskal.ts +21 -6
- package/src/algorithms/mst/prim.ts +13 -4
- package/src/algorithms/shortest-path/bellman-ford.ts +16 -28
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +38 -30
- package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
- package/src/algorithms/shortest-path/index.ts +5 -5
- package/src/algorithms/traversal/bfs-unified.ts +437 -0
- package/src/algorithms/traversal/bfs-variants.ts +520 -0
- package/src/algorithms/traversal/bfs.ts +5 -229
- package/src/algorithms/traversal/dfs.ts +61 -42
- package/src/algorithms/traversal/index.ts +3 -3
- package/src/benchmark-all-algorithms.ts +580 -0
- package/src/clustering/hierarchical.ts +268 -272
- package/src/clustering/index.ts +8 -6
- package/src/clustering/k-core.ts +93 -61
- package/src/clustering/mcl.ts +53 -23
- package/src/clustering/spectral.ts +130 -72
- package/src/core/graph.ts +58 -18
- package/src/data-structures/index.ts +2 -2
- package/src/data-structures/priority-queue.ts +36 -11
- package/src/data-structures/union-find.ts +22 -1
- package/src/flow/ford-fulkerson.ts +221 -262
- package/src/flow/min-cut.ts +59 -51
- package/src/index.ts +9 -2
- package/src/link-prediction/adamic-adar.ts +75 -74
- package/src/link-prediction/common-neighbors.ts +49 -49
- package/src/link-prediction/index.ts +1 -1
- package/src/optimized/bit-packed.ts +390 -0
- package/src/optimized/csr-graph.ts +518 -0
- package/src/optimized/direction-optimized-bfs.ts +310 -0
- package/src/optimized/graph-adapter.ts +248 -0
- package/src/optimized/index.ts +34 -0
- package/src/pathfinding/astar.ts +40 -25
- package/src/pathfinding/utils.ts +20 -13
- package/src/research/grsbm.ts +36 -39
- package/src/research/index.ts +4 -4
- package/src/research/sync.ts +41 -54
- package/src/research/terahac.ts +63 -21
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +269 -0
- package/src/utils/graph-utilities.ts +173 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +149 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +87 -0
- package/src/utils/priorityQueue.ts +40 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {Graph} from "../../core/graph.js";
|
|
2
|
-
import type {NodeId} from "../../types/index.js";
|
|
1
|
+
import { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
3
|
|
|
4
4
|
export interface FloydWarshallResult {
|
|
5
5
|
distances: Map<NodeId, Map<NodeId, number>>;
|
|
@@ -7,6 +7,11 @@ export interface FloydWarshallResult {
|
|
|
7
7
|
hasNegativeCycle: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Computes all-pairs shortest paths using the Floyd-Warshall algorithm
|
|
12
|
+
* @param graph - The graph to compute shortest paths for
|
|
13
|
+
* @returns The distances, predecessors, and negative cycle detection result
|
|
14
|
+
*/
|
|
10
15
|
export function floydWarshall(graph: Graph): FloydWarshallResult {
|
|
11
16
|
const nodes = Array.from(graph.nodes()).map((n) => n.id);
|
|
12
17
|
const distances = new Map<NodeId, Map<NodeId, number>>();
|
|
@@ -105,11 +110,18 @@ export function floydWarshall(graph: Graph): FloydWarshallResult {
|
|
|
105
110
|
};
|
|
106
111
|
}
|
|
107
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Finds the shortest path between two nodes using Floyd-Warshall
|
|
115
|
+
* @param graph - The graph to search
|
|
116
|
+
* @param source - The starting node for the path
|
|
117
|
+
* @param target - The destination node for the path
|
|
118
|
+
* @returns The path and distance or null if no path exists
|
|
119
|
+
*/
|
|
108
120
|
export function floydWarshallPath(
|
|
109
121
|
graph: Graph,
|
|
110
122
|
source: NodeId,
|
|
111
123
|
target: NodeId,
|
|
112
|
-
): {path: NodeId[]
|
|
124
|
+
): { path: NodeId[]; distance: number } | null {
|
|
113
125
|
const result = floydWarshall(graph);
|
|
114
126
|
|
|
115
127
|
if (!graph.hasNode(source) || !graph.hasNode(target)) {
|
|
@@ -146,12 +158,17 @@ export function floydWarshallPath(
|
|
|
146
158
|
|
|
147
159
|
if (current === source) {
|
|
148
160
|
path.unshift(source);
|
|
149
|
-
return {path, distance};
|
|
161
|
+
return { path, distance };
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
return null;
|
|
153
165
|
}
|
|
154
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Computes the transitive closure of a graph using Floyd-Warshall
|
|
169
|
+
* @param graph - The graph to compute transitive closure for
|
|
170
|
+
* @returns A map of each node to the set of nodes reachable from it
|
|
171
|
+
*/
|
|
155
172
|
export function transitiveClosure(graph: Graph): Map<NodeId, Set<NodeId>> {
|
|
156
173
|
const result = floydWarshall(graph);
|
|
157
174
|
const closure = new Map<NodeId, Set<NodeId>>();
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Shortest path algorithms
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export type {BellmanFordOptions, BellmanFordResult} from "./bellman-ford.js";
|
|
6
|
-
export {bellmanFord, bellmanFordPath, hasNegativeCycle} from "./bellman-ford.js";
|
|
7
|
-
export {allPairsShortestPath, dijkstra, dijkstraPath, singleSourceShortestPath} from "./dijkstra.js";
|
|
8
|
-
export type {FloydWarshallResult} from "./floyd-warshall.js";
|
|
9
|
-
export {floydWarshall, floydWarshallPath, transitiveClosure} from "./floyd-warshall.js";
|
|
5
|
+
export type { BellmanFordOptions, BellmanFordResult } from "./bellman-ford.js";
|
|
6
|
+
export { bellmanFord, bellmanFordPath, hasNegativeCycle } from "./bellman-ford.js";
|
|
7
|
+
export { allPairsShortestPath, dijkstra, dijkstraPath, singleSourceShortestPath } from "./dijkstra.js";
|
|
8
|
+
export type { FloydWarshallResult } from "./floyd-warshall.js";
|
|
9
|
+
export { floydWarshall, floydWarshallPath, transitiveClosure } from "./floyd-warshall.js";
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import { CSRGraph } from "../../optimized/csr-graph.js";
|
|
3
|
+
import { DirectionOptimizedBFS } from "../../optimized/direction-optimized-bfs.js";
|
|
4
|
+
import { toCSRGraph } from "../../optimized/graph-adapter.js";
|
|
5
|
+
import type { NodeId, ShortestPathResult, TraversalOptions, TraversalResult } from "../../types/index.js";
|
|
6
|
+
import { reconstructPath } from "../../utils/graph-utilities.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Unified BFS implementation that automatically optimizes for large graphs
|
|
10
|
+
*
|
|
11
|
+
* This module provides a single, user-friendly BFS implementation that:
|
|
12
|
+
* - Automatically uses Direction-Optimized BFS for large graphs (>10k nodes)
|
|
13
|
+
* - Maintains backward compatibility with existing APIs
|
|
14
|
+
* - Requires no configuration or understanding of optimization thresholds
|
|
15
|
+
* - Provides the best performance by default
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// Cache for CSR conversions to avoid repeated conversions
|
|
19
|
+
const csrCache = new WeakMap<Graph, CSRGraph>();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get or create CSR representation of a graph
|
|
23
|
+
* @param graph - The input graph to convert
|
|
24
|
+
* @returns CSR graph representation (cached for efficiency)
|
|
25
|
+
*/
|
|
26
|
+
function getCSRGraph(graph: Graph): CSRGraph {
|
|
27
|
+
let csrGraph = csrCache.get(graph);
|
|
28
|
+
if (!csrGraph) {
|
|
29
|
+
csrGraph = toCSRGraph(graph);
|
|
30
|
+
csrCache.set(graph, csrGraph);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return csrGraph;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Perform breadth-first search starting from a given node
|
|
38
|
+
*
|
|
39
|
+
* Automatically uses the most optimized implementation based on graph size.
|
|
40
|
+
* No configuration needed - just call this function for the best performance.
|
|
41
|
+
* @param graph - The input graph to traverse
|
|
42
|
+
* @param startNode - The node to start the BFS from
|
|
43
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
44
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
45
|
+
*/
|
|
46
|
+
export function breadthFirstSearch(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
47
|
+
if (!graph.hasNode(startNode)) {
|
|
48
|
+
throw new Error(`Start node ${String(startNode)} not found in graph`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Automatically use optimized implementation for large graphs
|
|
52
|
+
if (graph.nodeCount > 10000) {
|
|
53
|
+
return breadthFirstSearchOptimized(graph, startNode, options);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Standard implementation for smaller graphs
|
|
57
|
+
return breadthFirstSearchStandard(graph, startNode, options);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Standard BFS implementation for smaller graphs
|
|
62
|
+
* @param graph - The input graph to traverse
|
|
63
|
+
* @param startNode - The node to start the BFS from
|
|
64
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
65
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
66
|
+
*/
|
|
67
|
+
function breadthFirstSearchStandard(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
68
|
+
const visited = new Set<NodeId>();
|
|
69
|
+
const queue: { node: NodeId; level: number }[] = [];
|
|
70
|
+
const order: NodeId[] = [];
|
|
71
|
+
const tree = new Map<NodeId, NodeId | null>();
|
|
72
|
+
|
|
73
|
+
// Initialize with start node
|
|
74
|
+
queue.push({ node: startNode, level: 0 });
|
|
75
|
+
visited.add(startNode);
|
|
76
|
+
tree.set(startNode, null);
|
|
77
|
+
|
|
78
|
+
while (queue.length > 0) {
|
|
79
|
+
const current = queue.shift();
|
|
80
|
+
if (!current) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
order.push(current.node);
|
|
85
|
+
|
|
86
|
+
// Call visitor callback if provided
|
|
87
|
+
if (options.visitCallback) {
|
|
88
|
+
options.visitCallback(current.node, current.level);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Early termination if target found
|
|
92
|
+
if (options.targetNode && current.node === options.targetNode) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Explore neighbors
|
|
97
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
98
|
+
if (!visited.has(neighbor)) {
|
|
99
|
+
visited.add(neighbor);
|
|
100
|
+
tree.set(neighbor, current.node);
|
|
101
|
+
queue.push({ node: neighbor, level: current.level + 1 });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { visited, order, tree };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Optimized BFS implementation using Direction-Optimized BFS
|
|
111
|
+
* @param graph - The input graph to traverse
|
|
112
|
+
* @param startNode - The node to start the BFS from
|
|
113
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
114
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
115
|
+
*/
|
|
116
|
+
function breadthFirstSearchOptimized(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
117
|
+
const csrGraph = getCSRGraph(graph);
|
|
118
|
+
|
|
119
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
120
|
+
alpha: 15.0,
|
|
121
|
+
beta: 20.0,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const result = dobfs.search(startNode);
|
|
125
|
+
|
|
126
|
+
// Convert result to TraversalResult format
|
|
127
|
+
const visited = new Set<NodeId>();
|
|
128
|
+
const order: NodeId[] = [];
|
|
129
|
+
const tree = new Map<NodeId, NodeId | null>();
|
|
130
|
+
|
|
131
|
+
// Build traversal order using BFS from distances
|
|
132
|
+
const nodesByDistance = new Map<number, NodeId[]>();
|
|
133
|
+
let maxDistance = 0;
|
|
134
|
+
|
|
135
|
+
for (const [nodeId, distance] of result.distances) {
|
|
136
|
+
visited.add(nodeId);
|
|
137
|
+
tree.set(nodeId, result.parents.get(nodeId) ?? null);
|
|
138
|
+
|
|
139
|
+
if (!nodesByDistance.has(distance)) {
|
|
140
|
+
nodesByDistance.set(distance, []);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
nodesByDistance.get(distance)?.push(nodeId);
|
|
144
|
+
maxDistance = Math.max(maxDistance, distance);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Reconstruct BFS order
|
|
148
|
+
for (let d = 0; d <= maxDistance; d++) {
|
|
149
|
+
const nodes = nodesByDistance.get(d);
|
|
150
|
+
if (nodes) {
|
|
151
|
+
order.push(...nodes);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Handle visit callback if provided
|
|
156
|
+
if (options.visitCallback) {
|
|
157
|
+
for (const [nodeId, distance] of result.distances) {
|
|
158
|
+
options.visitCallback(nodeId, distance);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { visited, order, tree };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Find shortest path between two nodes using BFS
|
|
167
|
+
*
|
|
168
|
+
* Automatically optimized for large graphs. Returns null if no path exists.
|
|
169
|
+
* @param graph - The input graph to search
|
|
170
|
+
* @param source - The source node ID
|
|
171
|
+
* @param target - The target node ID
|
|
172
|
+
* @returns Shortest path result or null if no path exists
|
|
173
|
+
*/
|
|
174
|
+
export function shortestPathBFS(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
175
|
+
if (!graph.hasNode(source)) {
|
|
176
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!graph.hasNode(target)) {
|
|
180
|
+
throw new Error(`Target node ${String(target)} not found in graph`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Special case: source equals target
|
|
184
|
+
if (source === target) {
|
|
185
|
+
return {
|
|
186
|
+
distance: 0,
|
|
187
|
+
path: [source],
|
|
188
|
+
predecessor: new Map([[source, null]]),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Use optimized implementation for large graphs
|
|
193
|
+
if (graph.nodeCount > 10000) {
|
|
194
|
+
return shortestPathBFSOptimized(graph, source, target);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Standard implementation
|
|
198
|
+
return shortestPathBFSStandard(graph, source, target);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Standard shortest path BFS
|
|
203
|
+
* @param graph - The input graph to search
|
|
204
|
+
* @param source - The source node ID
|
|
205
|
+
* @param target - The target node ID
|
|
206
|
+
* @returns Shortest path result or null if no path exists
|
|
207
|
+
*/
|
|
208
|
+
function shortestPathBFSStandard(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
209
|
+
const visited = new Set<NodeId>();
|
|
210
|
+
const queue: { node: NodeId; distance: number }[] = [];
|
|
211
|
+
const predecessor = new Map<NodeId, NodeId | null>();
|
|
212
|
+
|
|
213
|
+
// Initialize BFS
|
|
214
|
+
queue.push({ node: source, distance: 0 });
|
|
215
|
+
visited.add(source);
|
|
216
|
+
predecessor.set(source, null);
|
|
217
|
+
|
|
218
|
+
while (queue.length > 0) {
|
|
219
|
+
const current = queue.shift();
|
|
220
|
+
if (!current) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Target found
|
|
225
|
+
if (current.node === target) {
|
|
226
|
+
const path = reconstructPath(target, predecessor);
|
|
227
|
+
return {
|
|
228
|
+
distance: current.distance,
|
|
229
|
+
path,
|
|
230
|
+
predecessor,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Explore neighbors
|
|
235
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
236
|
+
if (!visited.has(neighbor)) {
|
|
237
|
+
visited.add(neighbor);
|
|
238
|
+
predecessor.set(neighbor, current.node);
|
|
239
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// No path found
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Optimized shortest path using Direction-Optimized BFS
|
|
250
|
+
* @param graph - The input graph to search
|
|
251
|
+
* @param source - The source node ID
|
|
252
|
+
* @param target - The target node ID
|
|
253
|
+
* @returns Shortest path result or null if no path exists
|
|
254
|
+
*/
|
|
255
|
+
function shortestPathBFSOptimized(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
256
|
+
const csrGraph = getCSRGraph(graph);
|
|
257
|
+
|
|
258
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
259
|
+
alpha: 15.0,
|
|
260
|
+
beta: 20.0,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Perform BFS
|
|
264
|
+
const result = dobfs.search(source);
|
|
265
|
+
|
|
266
|
+
// Check if target was reached
|
|
267
|
+
const distance = result.distances.get(target);
|
|
268
|
+
if (distance === undefined) {
|
|
269
|
+
return null; // No path found
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Reconstruct path
|
|
273
|
+
const path = reconstructPath(target, result.parents);
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
distance,
|
|
277
|
+
path,
|
|
278
|
+
predecessor: result.parents,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Find shortest paths from source to all reachable nodes
|
|
284
|
+
*
|
|
285
|
+
* Automatically optimized for large graphs.
|
|
286
|
+
* @param graph - The input graph to search
|
|
287
|
+
* @param source - The source node ID to compute shortest paths from
|
|
288
|
+
* @returns Map of node IDs to their shortest path results
|
|
289
|
+
*/
|
|
290
|
+
export function singleSourceShortestPathBFS(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
291
|
+
if (!graph.hasNode(source)) {
|
|
292
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Use optimized implementation for large graphs
|
|
296
|
+
if (graph.nodeCount > 10000) {
|
|
297
|
+
return singleSourceShortestPathBFSOptimized(graph, source);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Standard implementation
|
|
301
|
+
return singleSourceShortestPathBFSStandard(graph, source);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Standard single-source shortest paths
|
|
306
|
+
* @param graph - The input graph to search
|
|
307
|
+
* @param source - The source node ID to compute shortest paths from
|
|
308
|
+
* @returns Map of node IDs to their shortest path results
|
|
309
|
+
*/
|
|
310
|
+
function singleSourceShortestPathBFSStandard(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
311
|
+
const results = new Map<NodeId, ShortestPathResult>();
|
|
312
|
+
const visited = new Set<NodeId>();
|
|
313
|
+
const queue: { node: NodeId; distance: number }[] = [];
|
|
314
|
+
const predecessor = new Map<NodeId, NodeId | null>();
|
|
315
|
+
const distances = new Map<NodeId, number>();
|
|
316
|
+
|
|
317
|
+
// Initialize BFS
|
|
318
|
+
queue.push({ node: source, distance: 0 });
|
|
319
|
+
visited.add(source);
|
|
320
|
+
predecessor.set(source, null);
|
|
321
|
+
distances.set(source, 0);
|
|
322
|
+
|
|
323
|
+
while (queue.length > 0) {
|
|
324
|
+
const current = queue.shift();
|
|
325
|
+
if (!current) {
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Explore neighbors
|
|
330
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
331
|
+
if (!visited.has(neighbor)) {
|
|
332
|
+
visited.add(neighbor);
|
|
333
|
+
predecessor.set(neighbor, current.node);
|
|
334
|
+
distances.set(neighbor, current.distance + 1);
|
|
335
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Build results after BFS completes
|
|
341
|
+
// This avoids copying the predecessor map for each node
|
|
342
|
+
for (const [node, distance] of distances) {
|
|
343
|
+
const path = reconstructPath(node, predecessor);
|
|
344
|
+
results.set(node, {
|
|
345
|
+
distance,
|
|
346
|
+
path,
|
|
347
|
+
predecessor, // Share the same predecessor map
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return results;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Optimized single-source shortest paths
|
|
356
|
+
* @param graph - The input graph to search
|
|
357
|
+
* @param source - The source node ID to compute shortest paths from
|
|
358
|
+
* @returns Map of node IDs to their shortest path results
|
|
359
|
+
*/
|
|
360
|
+
function singleSourceShortestPathBFSOptimized(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
361
|
+
const csrGraph = getCSRGraph(graph);
|
|
362
|
+
|
|
363
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
364
|
+
alpha: 15.0,
|
|
365
|
+
beta: 20.0,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const bfsResult = dobfs.search(source);
|
|
369
|
+
|
|
370
|
+
// Convert to expected format
|
|
371
|
+
const results = new Map<NodeId, ShortestPathResult>();
|
|
372
|
+
|
|
373
|
+
for (const [nodeId, distance] of bfsResult.distances) {
|
|
374
|
+
// Reconstruct path for each node
|
|
375
|
+
const path = reconstructPath(nodeId, bfsResult.parents);
|
|
376
|
+
|
|
377
|
+
results.set(nodeId, {
|
|
378
|
+
distance,
|
|
379
|
+
path,
|
|
380
|
+
predecessor: bfsResult.parents, // Share the same predecessor map
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return results;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Check if the graph is bipartite using BFS coloring
|
|
389
|
+
*
|
|
390
|
+
* Note: This function does not use Direction-Optimized BFS as the
|
|
391
|
+
* coloring logic is specific and doesn't benefit from the optimization.
|
|
392
|
+
* @param graph - The undirected graph to check
|
|
393
|
+
* @returns True if the graph is bipartite, false otherwise
|
|
394
|
+
*/
|
|
395
|
+
export function isBipartite(graph: Graph): boolean {
|
|
396
|
+
if (graph.isDirected) {
|
|
397
|
+
throw new Error("Bipartite test requires an undirected graph");
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const color = new Map<NodeId, 0 | 1>();
|
|
401
|
+
const visited = new Set<NodeId>();
|
|
402
|
+
|
|
403
|
+
// Check each connected component
|
|
404
|
+
for (const node of Array.from(graph.nodes())) {
|
|
405
|
+
if (!visited.has(node.id)) {
|
|
406
|
+
const queue: NodeId[] = [node.id];
|
|
407
|
+
color.set(node.id, 0);
|
|
408
|
+
visited.add(node.id);
|
|
409
|
+
|
|
410
|
+
while (queue.length > 0) {
|
|
411
|
+
const current = queue.shift();
|
|
412
|
+
if (!current) {
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const currentColor = color.get(current);
|
|
417
|
+
if (currentColor === undefined) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (const neighbor of Array.from(graph.neighbors(current))) {
|
|
422
|
+
if (!visited.has(neighbor)) {
|
|
423
|
+
// Color with opposite color
|
|
424
|
+
color.set(neighbor, currentColor === 0 ? 1 : 0);
|
|
425
|
+
visited.add(neighbor);
|
|
426
|
+
queue.push(neighbor);
|
|
427
|
+
} else if (color.get(neighbor) === currentColor) {
|
|
428
|
+
// Same color as current node - not bipartite
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return true;
|
|
437
|
+
}
|