| author | blanchet | 
| Tue, 07 Jun 2011 08:52:35 +0200 | |
| changeset 43228 | 2ed2f092e990 | 
| parent 39021 | 139aada5caf8 | 
| child 43792 | d5803c3d537a | 
| permissions | -rw-r--r-- | 
| 6134 | 1 | (* Title: Pure/General/graph.ML | 
| 15759 | 2 | Author: Markus Wenzel and Stefan Berghofer, TU Muenchen | 
| 6134 | 3 | |
| 4 | Directed graphs. | |
| 5 | *) | |
| 6 | ||
| 7 | signature GRAPH = | |
| 8 | sig | |
| 9 | type key | |
| 10 | type 'a T | |
| 9321 | 11 | exception DUP of key | 
| 19029 | 12 | exception SAME | 
| 13 | exception UNDEF of key | |
| 6134 | 14 | val empty: 'a T | 
| 28204 | 15 | val is_empty: 'a T -> bool | 
| 6659 | 16 | val keys: 'a T -> key list | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 17 | val dest: 'a T -> (key * key list) list | 
| 35012 
c3e3ac3ca091
removed unused "boundary" of Table/Graph.get_first;
 wenzelm parents: 
32710diff
changeset | 18 |   val get_first: (key * ('a * (key list * key list)) -> 'b option) -> 'a T -> 'b option
 | 
| 19615 | 19 |   val fold: (key * ('a * (key list * key list)) -> 'b -> 'b) -> 'a T -> 'b -> 'b
 | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 20 | val minimals: 'a T -> key list | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 21 | val maximals: 'a T -> key list | 
| 21935 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 22 | val subgraph: (key -> bool) -> 'a T -> 'a T | 
| 37853 | 23 | val get_entry: 'a T -> key -> 'a * (key list * key list) (*exception UNDEF*) | 
| 39021 | 24 | val map: (key -> 'a -> 'b) -> 'a T -> 'b T | 
| 15759 | 25 | val get_node: 'a T -> key -> 'a (*exception UNDEF*) | 
| 6142 | 26 |   val map_node: key -> ('a -> 'a) -> 'a T -> 'a T
 | 
| 17767 | 27 |   val map_node_yield: key -> ('a -> 'b * 'a) -> 'a T -> 'b * 'a T
 | 
| 6142 | 28 | val imm_preds: 'a T -> key -> key list | 
| 29 | val imm_succs: 'a T -> key -> key list | |
| 6134 | 30 | val all_preds: 'a T -> key list -> key list | 
| 31 | val all_succs: 'a T -> key list -> key list | |
| 14161 
73ad4884441f
Added function strong_conn for computing the strongly connected components
 berghofe parents: 
12451diff
changeset | 32 | val strong_conn: 'a T -> key list list | 
| 15759 | 33 | val new_node: key * 'a -> 'a T -> 'a T (*exception DUP*) | 
| 17179 | 34 | val default_node: key * 'a -> 'a T -> 'a T | 
| 15759 | 35 | val del_nodes: key list -> 'a T -> 'a T (*exception UNDEF*) | 
| 28333 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 36 | val del_node: key -> 'a T -> 'a T (*exception UNDEF*) | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 37 | val is_edge: 'a T -> key * key -> bool | 
| 6134 | 38 | val add_edge: key * key -> 'a T -> 'a T | 
| 6152 | 39 | val del_edge: key * key -> 'a T -> 'a T | 
| 23655 
d2d1138e0ddc
replaced exception TableFun/GraphFun.DUPS by TableFun/GraphFun.DUP;
 wenzelm parents: 
21935diff
changeset | 40 |   val merge: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T                 (*exception DUP*)
 | 
| 19029 | 41 | val join: (key -> 'a * 'a -> 'a) (*exception DUP/SAME*) -> | 
| 23655 
d2d1138e0ddc
replaced exception TableFun/GraphFun.DUPS by TableFun/GraphFun.DUP;
 wenzelm parents: 
21935diff
changeset | 42 | 'a T * 'a T -> 'a T (*exception DUP*) | 
| 19580 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 43 | val irreducible_paths: 'a T -> key * key -> key list list | 
| 20679 | 44 | val all_paths: 'a T -> key * key -> key list list | 
| 6142 | 45 | exception CYCLES of key list list | 
| 15759 | 46 | val add_edge_acyclic: key * key -> 'a T -> 'a T (*exception CYCLES*) | 
| 47 | val add_deps_acyclic: key * key list -> 'a T -> 'a T (*exception CYCLES*) | |
| 48 |   val merge_acyclic: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T         (*exception CYCLES*)
 | |
| 23964 | 49 | val topological_order: 'a T -> key list | 
| 15759 | 50 | val add_edge_trans_acyclic: key * key -> 'a T -> 'a T (*exception CYCLES*) | 
| 51 |   val merge_trans_acyclic: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T   (*exception CYCLES*)
 | |
| 6134 | 52 | end; | 
| 53 | ||
| 31971 
8c1b845ed105
renamed functor TableFun to Table, and GraphFun to Graph;
 wenzelm parents: 
31616diff
changeset | 54 | functor Graph(Key: KEY): GRAPH = | 
| 6134 | 55 | struct | 
| 56 | ||
| 57 | (* keys *) | |
| 58 | ||
| 59 | type key = Key.key; | |
| 60 | ||
| 18970 | 61 | val eq_key = is_equal o Key.ord; | 
| 6134 | 62 | |
| 18921 | 63 | val member_key = member eq_key; | 
| 15759 | 64 | val remove_key = remove eq_key; | 
| 6152 | 65 | |
| 6134 | 66 | |
| 67 | (* tables and sets of keys *) | |
| 68 | ||
| 31971 
8c1b845ed105
renamed functor TableFun to Table, and GraphFun to Graph;
 wenzelm parents: 
31616diff
changeset | 69 | structure Table = Table(Key); | 
| 6134 | 70 | type keys = unit Table.table; | 
| 71 | ||
| 6142 | 72 | val empty_keys = Table.empty: keys; | 
| 73 | ||
| 18921 | 74 | fun member_keys tab = Table.defined (tab: keys); | 
| 75 | fun insert_keys x tab = Table.insert (K true) (x, ()) (tab: keys); | |
| 6134 | 76 | |
| 77 | ||
| 6142 | 78 | (* graphs *) | 
| 6134 | 79 | |
| 80 | datatype 'a T = Graph of ('a * (key list * key list)) Table.table;
 | |
| 81 | ||
| 9321 | 82 | exception DUP = Table.DUP; | 
| 19029 | 83 | exception UNDEF = Table.UNDEF; | 
| 84 | exception SAME = Table.SAME; | |
| 6134 | 85 | |
| 86 | val empty = Graph Table.empty; | |
| 28204 | 87 | fun is_empty (Graph tab) = Table.is_empty tab; | 
| 6659 | 88 | fun keys (Graph tab) = Table.keys tab; | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 89 | fun dest (Graph tab) = map (fn (x, (_, (_, succs))) => (x, succs)) (Table.dest tab); | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 90 | |
| 35012 
c3e3ac3ca091
removed unused "boundary" of Table/Graph.get_first;
 wenzelm parents: 
32710diff
changeset | 91 | fun get_first f (Graph tab) = Table.get_first f tab; | 
| 19615 | 92 | fun fold_graph f (Graph tab) = Table.fold f tab; | 
| 93 | ||
| 94 | fun minimals G = fold_graph (fn (m, (_, ([], _))) => cons m | _ => I) G []; | |
| 95 | fun maximals G = fold_graph (fn (m, (_, (_, []))) => cons m | _ => I) G []; | |
| 6134 | 96 | |
| 21935 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 97 | fun subgraph P G = | 
| 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 98 | let | 
| 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 99 | fun subg (k, (i, (preds, succs))) = | 
| 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 100 | if P k then Table.update (k, (i, (filter P preds, filter P succs))) else I; | 
| 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 101 | in Graph (fold_graph subg G Table.empty) end; | 
| 
4e20a5397b57
renamed project to subgraph, improved presentation, avoided unnecessary evaluation of predicate;
 wenzelm parents: 
21565diff
changeset | 102 | |
| 6142 | 103 | fun get_entry (Graph tab) x = | 
| 17412 | 104 | (case Table.lookup tab x of | 
| 15531 | 105 | SOME entry => entry | 
| 106 | | NONE => raise UNDEF x); | |
| 6134 | 107 | |
| 17412 | 108 | fun map_entry x f (G as Graph tab) = Graph (Table.update (x, f (get_entry G x)) tab); | 
| 19290 | 109 | |
| 17767 | 110 | fun map_entry_yield x f (G as Graph tab) = | 
| 111 | let val (a, node') = f (get_entry G x) | |
| 112 | in (a, Graph (Table.update (x, node') tab)) end; | |
| 6134 | 113 | |
| 114 | ||
| 6142 | 115 | (* nodes *) | 
| 116 | ||
| 39021 | 117 | fun map_nodes f (Graph tab) = Graph (Table.map (apfst o f) tab); | 
| 6134 | 118 | |
| 6142 | 119 | fun get_node G = #1 o get_entry G; | 
| 18133 | 120 | |
| 6142 | 121 | fun map_node x f = map_entry x (fn (i, ps) => (f i, ps)); | 
| 19290 | 122 | |
| 17767 | 123 | fun map_node_yield x f = map_entry_yield x (fn (i, ps) => | 
| 124 | let val (a, i') = f i in (a, (i', ps)) end); | |
| 6142 | 125 | |
| 18133 | 126 | |
| 6142 | 127 | (* reachability *) | 
| 128 | ||
| 6659 | 129 | (*nodes reachable from xs -- topologically sorted for acyclic graphs*) | 
| 6142 | 130 | fun reachable next xs = | 
| 6134 | 131 | let | 
| 18006 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 132 | fun reach x (rs, R) = | 
| 18921 | 133 | if member_keys R x then (rs, R) | 
| 32710 | 134 | else fold reach (next x) (rs, insert_keys x R) |>> cons x; | 
| 135 | fun reachs x (rss, R) = | |
| 136 | reach x ([], R) |>> (fn rs => rs :: rss); | |
| 137 | in fold reachs xs ([], empty_keys) end; | |
| 6134 | 138 | |
| 6142 | 139 | (*immediate*) | 
| 140 | fun imm_preds G = #1 o #2 o get_entry G; | |
| 141 | fun imm_succs G = #2 o #2 o get_entry G; | |
| 6134 | 142 | |
| 6142 | 143 | (*transitive*) | 
| 32710 | 144 | fun all_preds G = flat o #1 o reachable (imm_preds G); | 
| 145 | fun all_succs G = flat o #1 o reachable (imm_succs G); | |
| 14161 
73ad4884441f
Added function strong_conn for computing the strongly connected components
 berghofe parents: 
12451diff
changeset | 146 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 147 | (*strongly connected components; see: David King and John Launchbury, | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 148 | "Structuring Depth First Search Algorithms in Haskell"*) | 
| 32710 | 149 | fun strong_conn G = | 
| 150 | rev (filter_out null (#1 (reachable (imm_preds G) (all_succs G (keys G))))); | |
| 6134 | 151 | |
| 18133 | 152 | |
| 9321 | 153 | (* nodes *) | 
| 6134 | 154 | |
| 6152 | 155 | fun new_node (x, info) (Graph tab) = | 
| 17412 | 156 | Graph (Table.update_new (x, (info, ([], []))) tab); | 
| 6134 | 157 | |
| 17179 | 158 | fun default_node (x, info) (Graph tab) = | 
| 159 | Graph (Table.default (x, (info, ([], []))) tab); | |
| 17140 | 160 | |
| 6659 | 161 | fun del_nodes xs (Graph tab) = | 
| 15759 | 162 | Graph (tab | 
| 163 | |> fold Table.delete xs | |
| 39020 | 164 | |> Table.map (fn _ => fn (i, (preds, succs)) => | 
| 15759 | 165 | (i, (fold remove_key xs preds, fold remove_key xs succs)))); | 
| 6659 | 166 | |
| 28333 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 167 | fun del_node x (G as Graph tab) = | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 168 | let | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 169 | fun del_adjacent which y = Table.map_entry y (fn (i, ps) => (i, (which (remove_key x) ps))); | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 170 | val (preds, succs) = #2 (get_entry G x); | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 171 | in | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 172 | Graph (tab | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 173 | |> Table.delete x | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 174 | |> fold (del_adjacent apsnd) preds | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 175 | |> fold (del_adjacent apfst) succs) | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 176 | end; | 
| 
507b64f4cd2a
added del_node, which is more efficient for sparse graphs;
 wenzelm parents: 
28204diff
changeset | 177 | |
| 6152 | 178 | |
| 9321 | 179 | (* edges *) | 
| 180 | ||
| 18921 | 181 | fun is_edge G (x, y) = member_key (imm_succs G x) y handle UNDEF _ => false; | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 182 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 183 | fun add_edge (x, y) G = | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 184 | if is_edge G (x, y) then G | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 185 | else | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 186 | G |> map_entry y (fn (i, (preds, succs)) => (i, (x :: preds, succs))) | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 187 | |> map_entry x (fn (i, (preds, succs)) => (i, (preds, y :: succs))); | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 188 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 189 | fun del_edge (x, y) G = | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 190 | if is_edge G (x, y) then | 
| 15759 | 191 | G |> map_entry y (fn (i, (preds, succs)) => (i, (remove_key x preds, succs))) | 
| 192 | |> map_entry x (fn (i, (preds, succs)) => (i, (preds, remove_key y succs))) | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 193 | else G; | 
| 9321 | 194 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 195 | fun diff_edges G1 G2 = | 
| 19482 
9f11af8f7ef9
tuned basic list operators (flat, maps, map_filter);
 wenzelm parents: 
19409diff
changeset | 196 | flat (dest G1 |> map (fn (x, ys) => ys |> map_filter (fn y => | 
| 15531 | 197 | if is_edge G2 (x, y) then NONE else SOME (x, y)))); | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 198 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 199 | fun edges G = diff_edges G empty; | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 200 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 201 | |
| 18126 | 202 | (* join and merge *) | 
| 203 | ||
| 18133 | 204 | fun no_edges (i, _) = (i, ([], [])); | 
| 205 | ||
| 35974 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 206 | fun join f (G1 as Graph tab1, G2 as Graph tab2) = | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 207 | let fun join_node key ((i1, edges1), (i2, _)) = (f key (i1, i2), edges1) in | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 208 | if pointer_eq (G1, G2) then G1 | 
| 39020 | 209 | else fold add_edge (edges G2) (Graph (Table.join join_node (tab1, Table.map (K no_edges) tab2))) | 
| 35974 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 210 | end; | 
| 6152 | 211 | |
| 35974 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 212 | fun gen_merge add eq (G1 as Graph tab1, G2 as Graph tab2) = | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 213 | let fun eq_node ((i1, _), (i2, _)) = eq (i1, i2) in | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 214 | if pointer_eq (G1, G2) then G1 | 
| 39020 | 215 | else fold add (edges G2) (Graph (Table.merge eq_node (tab1, Table.map (K no_edges) tab2))) | 
| 35974 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 216 | end; | 
| 6152 | 217 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 218 | fun merge eq GG = gen_merge add_edge eq GG; | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 219 | |
| 18133 | 220 | |
| 19580 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 221 | (* irreducible paths -- Hasse diagram *) | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 222 | |
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 223 | fun irreducible_preds G X path z = | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 224 | let | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 225 | fun red x x' = is_edge G (x, x') andalso not (eq_key (x', z)); | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 226 | fun irreds [] xs' = xs' | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 227 | | irreds (x :: xs) xs' = | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 228 | if not (member_keys X x) orelse eq_key (x, z) orelse member_key path x orelse | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 229 | exists (red x) xs orelse exists (red x) xs' | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 230 | then irreds xs xs' | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 231 | else irreds xs (x :: xs'); | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 232 | in irreds (imm_preds G z) [] end; | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 233 | |
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 234 | fun irreducible_paths G (x, y) = | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 235 | let | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 236 | val (_, X) = reachable (imm_succs G) [x]; | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 237 | fun paths path z = | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 238 | if eq_key (x, z) then cons (z :: path) | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 239 | else fold (paths (z :: path)) (irreducible_preds G X path z); | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 240 | in if eq_key (x, y) andalso not (is_edge G (x, x)) then [[]] else paths [] y [] end; | 
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 241 | |
| 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 242 | |
| 20736 | 243 | (* all paths *) | 
| 20679 | 244 | |
| 245 | fun all_paths G (x, y) = | |
| 246 | let | |
| 247 | val (_, X) = reachable (imm_succs G) [x]; | |
| 20736 | 248 | fun paths path z = | 
| 249 | if not (null path) andalso eq_key (x, z) then [z :: path] | |
| 250 | else if member_keys X z andalso not (member_key path z) | |
| 251 | then maps (paths (z :: path)) (imm_preds G z) | |
| 20679 | 252 | else []; | 
| 253 | in paths [] y end; | |
| 254 | ||
| 255 | ||
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 256 | (* maintain acyclic graphs *) | 
| 6142 | 257 | |
| 258 | exception CYCLES of key list list; | |
| 6134 | 259 | |
| 260 | fun add_edge_acyclic (x, y) G = | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 261 | if is_edge G (x, y) then G | 
| 9347 | 262 | else | 
| 19580 
c878a09fb849
replaced find_paths by irreducible_paths, i.e. produce paths within a Hasse diagram;
 wenzelm parents: 
19482diff
changeset | 263 | (case irreducible_paths G (y, x) of | 
| 9347 | 264 | [] => add_edge (x, y) G | 
| 265 | | cycles => raise CYCLES (map (cons x) cycles)); | |
| 6134 | 266 | |
| 15759 | 267 | fun add_deps_acyclic (y, xs) = fold (fn x => add_edge_acyclic (x, y)) xs; | 
| 9321 | 268 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 269 | fun merge_acyclic eq GG = gen_merge add_edge_acyclic eq GG; | 
| 9321 | 270 | |
| 23964 | 271 | fun topological_order G = minimals G |> all_succs G; | 
| 272 | ||
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 273 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 274 | (* maintain transitive acyclic graphs *) | 
| 9321 | 275 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 276 | fun add_edge_trans_acyclic (x, y) G = | 
| 19290 | 277 | add_edge_acyclic (x, y) G | 
| 25538 | 278 | |> fold_product (curry add_edge) (all_preds G [x]) (all_succs G [y]); | 
| 9321 | 279 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 280 | fun merge_trans_acyclic eq (G1, G2) = | 
| 35974 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 281 | if pointer_eq (G1, G2) then G1 | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 282 | else | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 283 | merge_acyclic eq (G1, G2) | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 284 | |> fold add_edge_trans_acyclic (diff_edges G1 G2) | 
| 
3a588b344749
low-level tuning for join/merge: ignore identical versions (SUBTLE CHANGE IN SEMANTICS);
 wenzelm parents: 
35405diff
changeset | 285 | |> fold add_edge_trans_acyclic (diff_edges G2 G1); | 
| 6134 | 286 | |
| 31540 | 287 | |
| 19615 | 288 | (*final declarations of this structure!*) | 
| 39021 | 289 | val map = map_nodes; | 
| 19615 | 290 | val fold = fold_graph; | 
| 291 | ||
| 6134 | 292 | end; | 
| 293 | ||
| 31971 
8c1b845ed105
renamed functor TableFun to Table, and GraphFun to Graph;
 wenzelm parents: 
31616diff
changeset | 294 | structure Graph = Graph(type key = string val ord = fast_string_ord); | 
| 35403 | 295 | structure Int_Graph = Graph(type key = int val ord = int_ord); |