11needsPackage " 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
67sparseStructure = (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
1820pathMult = (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
117128allTreks = (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