| author | paulson | 
| Mon, 09 Jan 2006 13:28:06 +0100 | |
| changeset 18623 | 9a5419d5ca01 | 
| parent 18133 | 1d403623dabc | 
| child 18921 | f47c46d7d654 | 
| permissions | -rw-r--r-- | 
| 6134 | 1 | (* Title: Pure/General/graph.ML | 
| 2 | ID: $Id$ | |
| 15759 | 3 | Author: Markus Wenzel and Stefan Berghofer, TU Muenchen | 
| 6134 | 4 | |
| 5 | Directed graphs. | |
| 6 | *) | |
| 7 | ||
| 8 | signature GRAPH = | |
| 9 | sig | |
| 10 | type key | |
| 11 | type 'a T | |
| 9321 | 12 | exception UNDEF of key | 
| 13 | exception DUP of key | |
| 14 | exception DUPS of key list | |
| 6134 | 15 | val empty: 'a T | 
| 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 | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 18 | val minimals: 'a T -> key list | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 19 | val maximals: 'a T -> key list | 
| 6142 | 20 |   val map_nodes: ('a -> 'b) -> 'a T -> 'b T
 | 
| 17767 | 21 | val fold_nodes: (key * 'b -> 'a -> 'a) -> 'b T -> 'a -> 'a | 
| 17580 | 22 | val fold_map_nodes: (key * 'b -> 'a -> 'c * 'a) -> 'b T -> 'a -> 'c T * 'a | 
| 15759 | 23 | val get_node: 'a T -> key -> 'a (*exception UNDEF*) | 
| 6142 | 24 |   val map_node: key -> ('a -> 'a) -> 'a T -> 'a T
 | 
| 17767 | 25 |   val map_node_yield: key -> ('a -> 'b * 'a) -> 'a T -> 'b * 'a T
 | 
| 6142 | 26 | val imm_preds: 'a T -> key -> key list | 
| 27 | val imm_succs: 'a T -> key -> key list | |
| 6134 | 28 | val all_preds: 'a T -> key list -> key list | 
| 29 | 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 | 30 | val strong_conn: 'a T -> key list list | 
| 17912 | 31 | val subgraph: key list -> 'a T -> 'a T | 
| 6134 | 32 | val find_paths: 'a T -> key * key -> 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*) | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 36 | val is_edge: 'a T -> key * key -> bool | 
| 6134 | 37 | val add_edge: key * key -> 'a T -> 'a T | 
| 6152 | 38 | val del_edge: key * key -> 'a T -> 'a T | 
| 15759 | 39 |   val merge: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T                 (*exception DUPS*)
 | 
| 18133 | 40 | val join: (key -> 'a * 'a -> 'a option) -> 'a T * 'a T -> 'a T (*exception DUPS*) | 
| 6142 | 41 | exception CYCLES of key list list | 
| 15759 | 42 | val add_edge_acyclic: key * key -> 'a T -> 'a T (*exception CYCLES*) | 
| 43 | val add_deps_acyclic: key * key list -> 'a T -> 'a T (*exception CYCLES*) | |
| 44 |   val merge_acyclic: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T         (*exception CYCLES*)
 | |
| 45 | val add_edge_trans_acyclic: key * key -> 'a T -> 'a T (*exception CYCLES*) | |
| 46 |   val merge_trans_acyclic: ('a * 'a -> bool) -> 'a T * 'a T -> 'a T   (*exception CYCLES*)
 | |
| 6134 | 47 | end; | 
| 48 | ||
| 49 | functor GraphFun(Key: KEY): GRAPH = | |
| 50 | struct | |
| 51 | ||
| 52 | (* keys *) | |
| 53 | ||
| 54 | type key = Key.key; | |
| 55 | ||
| 56 | val eq_key = equal EQUAL o Key.ord; | |
| 57 | ||
| 58 | infix mem_key; | |
| 59 | val op mem_key = gen_mem eq_key; | |
| 60 | ||
| 15759 | 61 | val remove_key = remove eq_key; | 
| 6152 | 62 | |
| 6134 | 63 | |
| 64 | (* tables and sets of keys *) | |
| 65 | ||
| 66 | structure Table = TableFun(Key); | |
| 67 | type keys = unit Table.table; | |
| 68 | ||
| 6142 | 69 | val empty_keys = Table.empty: keys; | 
| 70 | ||
| 6134 | 71 | infix mem_keys; | 
| 16894 | 72 | fun x mem_keys tab = Table.defined (tab: keys) x; | 
| 6134 | 73 | |
| 74 | infix ins_keys; | |
| 15759 | 75 | fun x ins_keys 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 UNDEF of key; | 
| 83 | exception DUP = Table.DUP; | |
| 84 | exception DUPS = Table.DUPS; | |
| 6134 | 85 | |
| 86 | val empty = Graph Table.empty; | |
| 6659 | 87 | fun keys (Graph tab) = Table.keys tab; | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 88 | 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 | 89 | |
| 16445 | 90 | fun minimals (Graph tab) = Table.fold (fn (m, (_, ([], _))) => cons m | _ => I) tab []; | 
| 91 | fun maximals (Graph tab) = Table.fold (fn (m, (_, (_, []))) => cons m | _ => I) tab []; | |
| 6134 | 92 | |
| 6142 | 93 | fun get_entry (Graph tab) x = | 
| 17412 | 94 | (case Table.lookup tab x of | 
| 15531 | 95 | SOME entry => entry | 
| 96 | | NONE => raise UNDEF x); | |
| 6134 | 97 | |
| 17412 | 98 | fun map_entry x f (G as Graph tab) = Graph (Table.update (x, f (get_entry G x)) tab); | 
| 17767 | 99 | fun map_entry_yield x f (G as Graph tab) = | 
| 100 | let val (a, node') = f (get_entry G x) | |
| 101 | in (a, Graph (Table.update (x, node') tab)) end; | |
| 6134 | 102 | |
| 103 | ||
| 6142 | 104 | (* nodes *) | 
| 105 | ||
| 106 | fun map_nodes f (Graph tab) = Graph (Table.map (fn (i, ps) => (f i, ps)) tab); | |
| 6134 | 107 | |
| 17767 | 108 | fun fold_nodes f (Graph tab) s = | 
| 109 | Table.fold (fn (k, (i, ps)) => f (k, i)) tab s | |
| 110 | ||
| 17580 | 111 | fun fold_map_nodes f (Graph tab) s = | 
| 112 | s | |
| 113 | |> Table.fold_map (fn (k, (i, ps)) => f (k, i) #> apfst (rpair ps)) tab | |
| 114 | |> apfst Graph; | |
| 115 | ||
| 6142 | 116 | fun get_node G = #1 o get_entry G; | 
| 18133 | 117 | |
| 6142 | 118 | fun map_node x f = map_entry x (fn (i, ps) => (f i, ps)); | 
| 17767 | 119 | fun map_node_yield x f = map_entry_yield x (fn (i, ps) => | 
| 120 | let val (a, i') = f i in (a, (i', ps)) end); | |
| 6142 | 121 | |
| 18133 | 122 | |
| 6142 | 123 | (* reachability *) | 
| 124 | ||
| 6659 | 125 | (*nodes reachable from xs -- topologically sorted for acyclic graphs*) | 
| 6142 | 126 | fun reachable next xs = | 
| 6134 | 127 | let | 
| 18006 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 128 | fun reach x (rs, R) = | 
| 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 129 | if x mem_keys R then (rs, R) | 
| 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 130 | else apfst (cons x) (fold reach (next x) (rs, x ins_keys R)) | 
| 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 131 | in fold_map (fn x => reach x o pair []) xs empty_keys end; | 
| 6134 | 132 | |
| 6142 | 133 | (*immediate*) | 
| 134 | fun imm_preds G = #1 o #2 o get_entry G; | |
| 135 | fun imm_succs G = #2 o #2 o get_entry G; | |
| 6134 | 136 | |
| 6142 | 137 | (*transitive*) | 
| 18006 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 138 | fun all_preds G = List.concat o fst o reachable (imm_preds G); | 
| 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 139 | fun all_succs G = List.concat o fst o reachable (imm_succs G); | 
| 14161 
73ad4884441f
Added function strong_conn for computing the strongly connected components
 berghofe parents: 
12451diff
changeset | 140 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 141 | (*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 | 142 | "Structuring Depth First Search Algorithms in Haskell"*) | 
| 18006 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 143 | fun strong_conn G = filter_out null (fst (reachable (imm_preds G) | 
| 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 144 | (List.concat (rev (fst (reachable (imm_succs G) (keys G))))))); | 
| 6134 | 145 | |
| 17912 | 146 | (*subgraph induced by node subset*) | 
| 147 | fun subgraph keys (Graph tab) = | |
| 148 | let | |
| 149 | val select = member eq_key keys; | |
| 150 | fun subg (k, (i, (preds, succs))) tab' = | |
| 151 | if select k | |
| 152 | then tab' |> Table.update (k, (i, (filter select preds, filter select succs))) | |
| 153 | else tab' | |
| 154 | in Table.empty |> Table.fold subg tab |> Graph end; | |
| 6134 | 155 | |
| 18133 | 156 | |
| 6142 | 157 | (* paths *) | 
| 6134 | 158 | |
| 159 | fun find_paths G (x, y) = | |
| 160 | let | |
| 18006 
535de280c812
reachable - abandoned foldl_map in favor of fold_map
 haftmann parents: 
17912diff
changeset | 161 | val (_, X) = reachable (imm_succs G) [x]; | 
| 6134 | 162 | fun paths ps p = | 
| 12451 | 163 | if not (null ps) andalso eq_key (p, x) then [p :: ps] | 
| 164 | else if p mem_keys X andalso not (p mem_key ps) | |
| 15570 | 165 | then List.concat (map (paths (p :: ps)) (imm_preds G p)) | 
| 12451 | 166 | else []; | 
| 167 | in paths [] y end; | |
| 6134 | 168 | |
| 169 | ||
| 9321 | 170 | (* nodes *) | 
| 6134 | 171 | |
| 6152 | 172 | fun new_node (x, info) (Graph tab) = | 
| 17412 | 173 | Graph (Table.update_new (x, (info, ([], []))) tab); | 
| 6134 | 174 | |
| 17179 | 175 | fun default_node (x, info) (Graph tab) = | 
| 176 | Graph (Table.default (x, (info, ([], []))) tab); | |
| 17140 | 177 | |
| 6659 | 178 | fun del_nodes xs (Graph tab) = | 
| 15759 | 179 | Graph (tab | 
| 180 | |> fold Table.delete xs | |
| 181 | |> Table.map (fn (i, (preds, succs)) => | |
| 182 | (i, (fold remove_key xs preds, fold remove_key xs succs)))); | |
| 6659 | 183 | |
| 6152 | 184 | |
| 9321 | 185 | (* edges *) | 
| 186 | ||
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 187 | fun is_edge G (x, y) = y mem_key imm_succs G x handle UNDEF _ => false; | 
| 
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 add_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 G | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 191 | else | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 192 | 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 | 193 | |> 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 | 194 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 195 | fun del_edge (x, y) G = | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 196 | if is_edge G (x, y) then | 
| 15759 | 197 | G |> map_entry y (fn (i, (preds, succs)) => (i, (remove_key x preds, succs))) | 
| 198 | |> 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 | 199 | else G; | 
| 9321 | 200 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 201 | fun diff_edges G1 G2 = | 
| 15570 | 202 | List.concat (dest G1 |> map (fn (x, ys) => ys |> List.mapPartial (fn y => | 
| 15531 | 203 | 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 | 204 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 205 | fun edges G = diff_edges G empty; | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 206 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 207 | |
| 18126 | 208 | (* join and merge *) | 
| 209 | ||
| 18133 | 210 | fun no_edges (i, _) = (i, ([], [])); | 
| 211 | ||
| 212 | fun join f (Graph tab1, G2 as Graph tab2) = | |
| 18126 | 213 | let | 
| 214 | fun join_node key ((i1, edges1), (i2, _)) = | |
| 215 | (Option.map (rpair edges1) o f key) (i1, i2); | |
| 18133 | 216 | in fold add_edge (edges G2) (Graph (Table.join join_node (tab1, Table.map no_edges tab2))) end; | 
| 6152 | 217 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 218 | fun gen_merge add eq (Graph tab1, G2 as Graph tab2) = | 
| 18133 | 219 | let fun eq_node ((i1, _), (i2, _)) = eq (i1, i2) | 
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 220 | in fold add (edges G2) (Graph (Table.merge eq_node (tab1, Table.map no_edges tab2))) end; | 
| 6152 | 221 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 222 | 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 | 223 | |
| 18133 | 224 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 225 | (* maintain acyclic graphs *) | 
| 6142 | 226 | |
| 227 | exception CYCLES of key list list; | |
| 6134 | 228 | |
| 229 | fun add_edge_acyclic (x, y) G = | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 230 | if is_edge G (x, y) then G | 
| 9347 | 231 | else | 
| 232 | (case find_paths G (y, x) of | |
| 233 | [] => add_edge (x, y) G | |
| 234 | | cycles => raise CYCLES (map (cons x) cycles)); | |
| 6134 | 235 | |
| 15759 | 236 | fun add_deps_acyclic (y, xs) = fold (fn x => add_edge_acyclic (x, y)) xs; | 
| 9321 | 237 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 238 | fun merge_acyclic eq GG = gen_merge add_edge_acyclic eq GG; | 
| 9321 | 239 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 240 | |
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 241 | (* maintain transitive acyclic graphs *) | 
| 9321 | 242 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 243 | fun add_edge_trans_acyclic (x, y) G = | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 244 | add_edge_acyclic (x, y) G |> | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 245 | fold add_edge (Library.product (all_preds G [x]) (all_succs G [y])); | 
| 9321 | 246 | |
| 14793 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 247 | fun merge_trans_acyclic eq (G1, G2) = | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 248 | merge_acyclic eq (G1, G2) |> | 
| 
32d94d1e4842
added dest, minimals, maximals, is_edge, add_edge/merge_trans_acyclic;
 wenzelm parents: 
14161diff
changeset | 249 | fold add_edge_trans_acyclic (diff_edges G1 G2 @ diff_edges G2 G1); | 
| 6134 | 250 | |
| 251 | end; | |
| 252 | ||
| 253 | ||
| 254 | (*graphs indexed by strings*) | |
| 16810 | 255 | structure Graph = GraphFun(type key = string val ord = fast_string_ord); |