2014-07-14 19:32:44 +00:00
|
|
|
(*
|
2020-03-09 06:18:30 +00:00
|
|
|
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
2014-07-14 19:32:44 +00:00
|
|
|
*
|
2020-03-09 06:18:30 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2014-07-14 19:32:44 +00:00
|
|
|
*)
|
|
|
|
|
|
|
|
signature TOPO_SORT =
|
|
|
|
sig
|
|
|
|
|
|
|
|
val topo_sort : {cmp: 'a * 'a -> order, graph : 'a -> 'a list,
|
|
|
|
converse : 'a -> 'a list} ->
|
|
|
|
'a list ->
|
|
|
|
'a list list
|
|
|
|
(* a "topological sort" that sorts the graph into topologically ordered
|
|
|
|
strongly connected components, using Tarjan's algorithm. *)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2015-11-09 03:44:50 +00:00
|
|
|
structure Topo_Sort : TOPO_SORT =
|
2014-07-14 19:32:44 +00:00
|
|
|
struct
|
|
|
|
|
|
|
|
fun dfs_finishes (cmp, neighbours) nodes = let
|
|
|
|
datatype 'a action = Visit of 'a | Finish of 'a
|
|
|
|
fun recurse visited result actlist =
|
|
|
|
case actlist of
|
|
|
|
[] => result
|
|
|
|
| Visit n :: rest => if Binaryset.member(visited, n) then
|
|
|
|
recurse visited result rest
|
|
|
|
else let
|
|
|
|
val ns = map Visit (neighbours n)
|
|
|
|
in
|
|
|
|
recurse (Binaryset.add(visited, n))
|
|
|
|
result
|
|
|
|
(ns @ (Finish n :: rest))
|
|
|
|
end
|
|
|
|
| Finish n :: rest => recurse visited (n::result) rest
|
|
|
|
in
|
|
|
|
recurse (Binaryset.empty cmp) [] (map Visit nodes)
|
|
|
|
end
|
|
|
|
|
2015-11-09 03:44:50 +00:00
|
|
|
fun fcons _ [] = raise Fail "Should never happen"
|
2014-07-14 19:32:44 +00:00
|
|
|
| fcons x (h::t) = (x::h) :: t
|
|
|
|
fun dfs_trees (cmp, neighbours) nodes = let
|
|
|
|
datatype 'a action = Visit of 'a | Initial of 'a
|
|
|
|
fun recurse visited result actlist =
|
|
|
|
case actlist of
|
|
|
|
[] => result
|
|
|
|
| Initial n :: rest => if Binaryset.member(visited,n) then
|
|
|
|
recurse visited result rest
|
|
|
|
else
|
|
|
|
recurse (Binaryset.add(visited, n))
|
|
|
|
([n] :: result)
|
|
|
|
(map Visit (neighbours n) @ rest)
|
|
|
|
| Visit n :: rest => if Binaryset.member(visited, n) then
|
|
|
|
recurse visited result rest
|
|
|
|
else
|
|
|
|
recurse (Binaryset.add(visited, n))
|
|
|
|
(fcons n result)
|
|
|
|
(map Visit (neighbours n) @ rest)
|
|
|
|
in
|
|
|
|
recurse (Binaryset.empty cmp) [] (map Initial nodes)
|
|
|
|
end
|
|
|
|
|
|
|
|
fun topo_sort {cmp, graph, converse} nodes =
|
|
|
|
dfs_trees (cmp, converse) (dfs_finishes (cmp, graph) nodes)
|
|
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
fun ns 0 = [1]
|
|
|
|
| ns 1 = [2,3]
|
|
|
|
| ns 2 = []
|
|
|
|
| ns 3 = [5,7]
|
|
|
|
| ns 4 = []
|
|
|
|
| ns 5 = [8,9]
|
|
|
|
| ns 6 = []
|
|
|
|
| ns 7 = [3,4,6]
|
|
|
|
| ns 8 = [5]
|
|
|
|
| ns 9 = [];
|
|
|
|
fun ns' 0 = []
|
|
|
|
| ns' 1 = [0]
|
|
|
|
| ns' 2 = [1]
|
|
|
|
| ns' 3 = [1,7]
|
|
|
|
| ns' 4 = [7]
|
|
|
|
| ns' 5 = [3,8]
|
|
|
|
| ns' 6 = [7]
|
|
|
|
| ns' 7 = [3]
|
|
|
|
| ns' 8 = [5]
|
|
|
|
| ns' 9 = [5];
|
|
|
|
|
|
|
|
fun eg235 n =
|
|
|
|
case n of
|
|
|
|
1 => [2]
|
|
|
|
| 2 => [3,5,6]
|
|
|
|
| 3 => [4,7]
|
|
|
|
| 4 => [3,8]
|
|
|
|
| 5 => [1,6]
|
|
|
|
| 6 => [7]
|
|
|
|
| 7 => [6,8]
|
|
|
|
| 8 => [8]
|
|
|
|
fun eg235' n =
|
|
|
|
case n of
|
|
|
|
1 => [5]
|
|
|
|
| 2 => [1]
|
|
|
|
| 3 => [2,4]
|
|
|
|
| 4 => [3]
|
|
|
|
| 5 => [2]
|
|
|
|
| 6 => [2,5,7]
|
|
|
|
| 7 => [3,6]
|
|
|
|
| 8 => [8]
|
|
|
|
|
|
|
|
val sscs = dfs_trees (Int.compare, eg235')
|
|
|
|
(dfs_finishes (Int.compare, eg235) [1,2,3,4,5,6,7,8])
|
|
|
|
*)
|
|
|
|
end; (* struct *)
|