Skip to content

Commit 46e102a

Browse files
committed
Update treksDynamic.m2
1 parent e4e3cef commit 46e102a

File tree

1 file changed

+54
-41
lines changed

1 file changed

+54
-41
lines changed

treksDynamic.m2

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,42 @@
11
needsPackage "GraphicalModels"
22

33

4-
-- idea of the code: compute all directed paths in G afterwards combine them to compute all Treks
4+
-- idea of the code: compute all directed paths in G; combine them pairwise to compute all Treks
5+
-- use matrix multiplication for the adjacency matrix, where multilplication corresponds to enlarging the path and addition corresponds to finding another path
56

67
sparseStructure = (G, direction) -> (
7-
-- structure for computations, stores start-vertex, end-vertex and edge betreen them -> later all paths of length k between them
88
E = edges(G);
99
if direction == +1 then (
10+
-- structure for computations, stores start-vertex, end-vertex and edge betreen them -> later all paths of length k between them
1011
return new HashTable from apply(E, i -> i#0 => new HashTable from apply(E, j -> if (i#0 == j#0) then (j#1 => j)))
1112
)
1213
else (
14+
-- has vertex any edge ending in it
1315
return new HashTable from apply(E, i -> i#1 => true)
1416
);
1517
)
1618

17-
-- "multiply" current k-th power of the adjacency matrix (paths) with adjacency matrix to get paths of length k+1
19+
-- multiply k-th power of the adjacency matrix (paths) with adjacency matrix to get paths of length k+1
1820
pathMult = (edgs, paths, rev) -> (
1921
ext = new MutableHashTable from {};
2022
for start in keys(paths) do (
2123
for endpoint in keys(rev) do (
24+
-- compute (start, endpoint) in outputmatrix
2225
extpaths = new MutableList from {};
2326
for mid in keys(paths#start) do (
2427
if edgs#?mid and edgs#mid#?endpoint then (
28+
-- there exist at least one path (start --- mid - endpoint) of lenght n+1
2529
if class(paths#start#mid#0) === List then (
30+
-- resolve case of multiple paths of the form start -- mid
2631
for extpath in paths#start#mid do (extpaths##extpaths = flatten({extpath, endpoint}))
2732
)
2833
else (extpaths##extpaths = flatten({paths#start#mid, endpoint}))
2934
);
3035
);
3136
extpaths = new List from extpaths;
32-
if not(extpaths#?1) then (
33-
extpaths = flatten(extpaths);
34-
);
37+
-- resolve case of just one vertex mid connecting start and end
38+
if not(extpaths#?1) then extpaths = flatten(extpaths);
39+
-- write outputmatrix
3540
if #extpaths > 0 then(
3641
if not ext#?start then (ext#start = new MutableHashTable from {endpoint => extpaths})
3742
else (ext#start#endpoint = extpaths);
@@ -42,14 +47,19 @@ pathMult = (edgs, paths, rev) -> (
4247
)
4348

4449

45-
-- first code computes all powers of sparse version of adjacency matrix
46-
pathGen = (G) -> (
47-
V = vertices(G);
50+
-- first variant for computing all paths: computes powers of sparse version of adjacency matrix
51+
pathGen = (G, V) -> (
4852
rev = sparseStructure(G, -1);
4953
-- i-th entry of paths has all paths of leghth i in G
5054
paths = new MutableList from {new HashTable from apply(V, v-> v => new HashTable from {v => {v}}), sparseStructure(G, +1)};
51-
while #keys(paths#(#paths-1)) > 0 do (paths##paths = pathMult(paths#1, paths#(#paths-1), rev));
52-
-- combine all of the hashtables into one
55+
-- basic infinite loop prevention
56+
pathlen = 1;
57+
while #keys(paths#(#paths-1)) > 0 do (
58+
paths##paths = pathMult(paths#1, paths#(#paths-1), rev);
59+
pathlen = pathlen +1;
60+
);
61+
if #keys(paths#(#paths-1)) > 0 then error "the graph is not acyclic";
62+
-- combine all of the hashtables into one (startpoint => endpoint => {all paths between them})
5363
combpaths = new MutableHashTable from apply(V, v -> v => new MutableHashTable from apply(V, w -> w => new MutableList from {}));
5464
for pathlength in apply((#paths-1), v->paths#v) do (
5565
for startp in keys(pathlength) do (
@@ -69,75 +79,78 @@ pathGen = (G) -> (
6979
)
7080

7181

72-
-- second code computes reverse version of bfs which only apends elements to queue if all paths starting from it are found
73-
BfsPathGen = (G) -> (
82+
-- second variant for computing all paths: computes reverse version of bfs which only apends elements to queue if all paths starting from it are found
83+
BfsPathGen = (G, V) -> (
7484
-- input digraph G, output all paths in G
75-
V = vertices (G);
7685
E = edges(G);
7786
exitdegrees = new MutableHashTable from apply(V, v -> v => degreeOut(G, v));
78-
pathsStartingInVertex = new MutableHashTable from apply(V, v -> v => new MutableHashTable from apply(V, w -> w => new MutableList from {}));
87+
pathtable = new MutableHashTable from apply(V, v -> v => new MutableHashTable from apply(V, w -> w => new MutableList from {}));
7988
endingEdges = new MutableHashTable from apply(V, v -> v => new MutableHashTable from {});
8089
for edge in E do (
8190
endingEdges#(edge#1)#(edge#0) = edge;
8291
);
8392
queue = new MutableList from select(apply(V, v-> if exitdegrees#v == 0 then v), x-> not(x === null));
8493
current = 0;
8594
while current < #V do(
95+
if #queue == current then error "the graph is not acyclic";
8696
topVert = queue#current;
8797
for found in keys(endingEdges#topVert) do (
8898
exitdegrees#found = exitdegrees#found -1;
8999
if exitdegrees#found == 0 then queue##queue = found;
90-
(pathsStartingInVertex#found#topVert)##(pathsStartingInVertex#found#topVert) = {found,topVert};
91-
for keyext in keys(pathsStartingInVertex#topVert) do (
92-
if #(pathsStartingInVertex#topVert#keyext) > 0 then (
93-
for pathext in pathsStartingInVertex#topVert#keyext do (
94-
(pathsStartingInVertex#found#keyext)##(pathsStartingInVertex#found#keyext) = flatten({found, pathext});
100+
(pathtable#found#topVert)##(pathtable#found#topVert) = {found,topVert};
101+
for keyext in keys(pathtable#topVert) do (
102+
if #(pathtable#topVert#keyext) > 0 then (
103+
for pathext in pathtable#topVert#keyext do (
104+
(pathtable#found#keyext)##(pathtable#found#keyext) = flatten({found, pathext});
95105
);
96106
);
97107
);
98108
);
99109
current = current +1;
100110
);
101-
apply(V, v -> (pathsStartingInVertex#v#v)##(pathsStartingInVertex#v#v) = {v});
102-
return pathsStartingInVertex
111+
apply(V, v -> (pathtable#v#v)##(pathtable#v#v) = {v});
112+
return pathtable
103113
)
104114

105115
---
106-
--G = digraph {{1, {2,3,4,5,6,7,8,9}}, {2, {3,4,5,6,7,8,9}}, {3, {4,5,6,7,8,9}}, {4,{5,6,7,8,9}}, {5, {6,7,8,9}}, {6, {7,8,9}}, {7, {8,9}}, {8, {9}}}
116+
-- G = digraph {{1, {2,3,4,5,6,7,8,9}}, {2, {3,4,5,6,7,8,9}}, {3, {4,5,6,7,8,9}}, {4,{5,6,7,8,9}}, {5, {6,7,8,9}}, {6, {7,8,9}}, {7, {8,9}}, {8, {9}}}
107117

108-
--sum(apply(1000, x -> (elapsedTiming(pathGen(G)))#0))
109-
--sum(apply(1000, x -> (elapsedTiming(BfsPathGen(G)))#0))
118+
-- sum(apply(1000, x -> (elapsedTiming(pathGen(G)))#0))
119+
-- sum(apply(1000, x -> (elapsedTiming(BfsPathGen(G)))#0))
110120

111121
-- from my testting Bfs is better in non-sparse situations while normal is faster in sparse graphs
112122
-- none of them have propper loop protection (for cyclic graphs) at the moment
113123
---
114124

115125

116126

127+
-- for application need (top, path1, path2) where top is source of both paths -> tensor endpoint1 => endpont2 => top => all treks connecting them
117128
allTreks = (G) -> (
118-
-- this computation takes up almost all of the running time
119-
-- can be improved by propperly choosing just the necessary midpoints for each pair
120-
-- can be improved by just computing for end2>end1 and use symmetry
121129
V = vertices (G);
122-
paths = pathGen(G);
123-
--paths = BfsPathGen(G);
124-
treks = new MutableHashTable from apply(V, v -> v => new MutableHashTable from apply(V, w -> w => new MutableList from {}));
125-
for end1 in V do (
126-
for end2 in V do(
127-
for mid in V do (
128-
if #(paths#mid#end1)>0 and #(paths#mid#end2)>0 then (
129-
for trek1 in paths#mid#end1 do (
130-
for trek2 in paths#mid#end2 do(
131-
(treks#end1#end2)##(treks#end1#end2) = (reverse(trek1), trek2);
130+
paths = pathGen(G, V);
131+
--paths = BfsPathGen(G, V);
132+
treks = new MutableHashTable from apply(V, e1 -> e1 => new MutableHashTable from apply(V, e2 -> e2 => new MutableHashTable from apply(V, t -> t => new MutableList from {})));
133+
for topvertex in keys(paths) do(
134+
endpoints = keys(paths#topvertex);
135+
if #endpoints > 1 then(
136+
for index1 from 0 to #endpoints-2 do(
137+
for index2 from index1+1 to #endpoints-1 do(
138+
end1 = endpoints#index1;
139+
end2 = endpoints#index2;
140+
for trek1 in paths#topvertex#end1 do (
141+
for trek2 in paths#topvertex#end2 do(
142+
(treks#end1#end2#topvertex)##(treks#end1#end2#topvertex) = (reverse(trek1), trek2);
143+
(treks#end2#end1#topvertex)##(treks#end2#end1#topvertex) = (reverse(trek2), trek1);
132144
);
133145
);
134146
);
135147
);
136148
);
149+
-- im not sure how to save the other case (treks of the length one) for application afterwards- needs to be done here
137150
);
138151
return treks
139152
)
140153

141-
--G = digraph {{1, {2,3,4,5,6,7,8,9}}, {2, {3,4,5,6,7,8,9}}, {3, {4,5,6,7,8,9}}, {4,{5,6,7,8,9}}, {5, {6,7,8,9}}, {6, {7,8,9}}, {7, {8,9}}, {8, {9}}}
142-
--(elapsedTiming(allTreks(G)))#0
143-
--sum(apply(10, x -> (elapsedTiming(allTreks(G)))#0))
154+
-- G = digraph {{1, {2,3,4,5,6,7,8,9}}, {2, {3,4,5,6,7,8,9}}, {3, {4,5,6,7,8,9}}, {4,{5,6,7,8,9}}, {5, {6,7,8,9}}, {6, {7,8,9}}, {7, {8,9}}, {8, {9}}}
155+
-- (elapsedTiming(allTreks(G)))#0
156+
-- sum(apply(10, x -> (elapsedTiming(allTreks(G)))#0))

0 commit comments

Comments
 (0)