Topological sort: Difference between revisions
Content added Content deleted
Line 526: | Line 526: | ||
in |
in |
||
abstype |
abstype marks (n : int) |
||
assume |
assume marks n = _marksvec_t n |
||
fn |
fn marks_make_elt |
||
{n : nat} |
{n : nat} |
||
{b : int | b == 0 || b == 1} |
{b : int | b == 0 || b == 1} |
||
Line 538: | Line 538: | ||
fn |
fn |
||
marks_set_at |
|||
marks_t_set_at |
|||
{n : int} |
{n : int} |
||
{i : nat | i < n} |
{i : nat | i < n} |
||
Line 549: | Line 549: | ||
fn |
fn |
||
marks_get_at |
|||
marks_t_get_at |
|||
{n : int} |
{n : int} |
||
{i : nat | i < n} |
{i : nat | i < n} |
||
Line 559: | Line 559: | ||
fn |
fn |
||
marks_setall |
|||
marks_t_setall |
|||
{n : int} |
{n : int} |
||
{b : int | b == 0 || b == 1} |
{b : int | b == 0 || b == 1} |
||
Line 577: | Line 577: | ||
end |
end |
||
overload [] with |
overload [] with marks_set_at of 100 |
||
overload [] with |
overload [] with marks_get_at of 100 |
||
overload setall with |
overload setall with marks_setall of 100 |
||
end |
end |
||
Line 592: | Line 592: | ||
entries of each sublist forms the list of dependencies of the first |
entries of each sublist forms the list of dependencies of the first |
||
entry. Thus this is a kind of association list. *) |
entry. Thus this is a kind of association list. *) |
||
typedef |
typedef depdesc (n : int) = list (List1 String1, n) |
||
typedef |
typedef depdesc = [n : nat] depdesc n |
||
typedef |
typedef char_skipper = |
||
{n : int} |
{n : int} |
||
{i : nat | i <= n} |
{i : nat | i <= n} |
||
Line 607: | Line 607: | ||
make_char_skipper |
make_char_skipper |
||
(match : char -<> bool) |
(match : char -<> bool) |
||
:<> |
:<> char_skipper = |
||
let |
let |
||
fun |
fun |
||
Line 679: | Line 679: | ||
i : size_t i) |
i : size_t i) |
||
:<!wrt> [j : int | i <= j; j <= n] |
:<!wrt> [j : int | i <= j; j <= n] |
||
@( |
@(depdesc, size_t j) = |
||
let |
let |
||
fun |
fun |
||
loop {i : nat | i <= n} |
loop {i : nat | i <= n} |
||
.<n - i>. |
.<n - i>. |
||
(desc : |
(desc : depdesc, |
||
i : size_t i) |
i : size_t i) |
||
:<!wrt> [j : int | i <= j; j <= n] |
:<!wrt> [j : int | i <= j; j <= n] |
||
@( |
@(depdesc, size_t j) = |
||
let |
let |
||
val i = skip_spaces (text, n, i) |
val i = skip_spaces (text, n, i) |
||
Line 732: | Line 732: | ||
fn |
fn |
||
read_depdesc () |
read_depdesc () |
||
: |
: depdesc = |
||
let |
let |
||
val text = read_to_string () |
val text = read_to_string () |
||
Line 747: | Line 747: | ||
(* An ordered list of the node names. *) |
(* An ordered list of the node names. *) |
||
typedef |
typedef nodenames (n : int) = list (String1, n) |
||
(* A more efficient representation for nodes: integers in 0..n. *) |
(* A more efficient representation for nodes: integers in 0..n. *) |
||
typedef |
typedef nodenum (n : int) = [num : nat | num <= n - 1] size_t num |
||
(* A collection of directed edges. *) |
(* A collection of directed edges. *) |
||
typedef |
typedef edges (n : int) = arrayref (List0 (nodenum n), n) |
||
(* An internal representation of data for a topological sort. *) |
(* An internal representation of data for a topological sort. *) |
||
typedef |
typedef topodata (n : int) = |
||
'{ |
'{ |
||
n = size_t n, (* The number of nodes. *) |
n = size_t n, (* The number of nodes. *) |
||
edges = |
edges = edges n, (* Directed edges. *) |
||
tempmarks = |
tempmarks = marks n, (* Temporary marks. *) |
||
permmarks = |
permmarks = marks n (* Permanent marks. *) |
||
} |
} |
||
fn |
fn |
||
collect_nodenames |
collect_nodenames |
||
(desc : |
(desc : depdesc) |
||
:<!wrt> [n : nat] |
:<!wrt> [n : nat] |
||
@( |
@(nodenames n, |
||
size_t n) = |
size_t n) = |
||
let |
let |
||
Line 777: | Line 777: | ||
.<m>. |
.<m>. |
||
(row : list (String1, m), |
(row : list (String1, m), |
||
names : & |
names : &nodenames n0 >> nodenames n1, |
||
n : &size_t n0 >> size_t n1) |
n : &size_t n0 >> size_t n1) |
||
:<!wrt> #[n1 : int | n0 <= n1] |
:<!wrt> #[n1 : int | n0 <= n1] |
||
Line 802: | Line 802: | ||
.<m>. |
.<m>. |
||
(desc : list (List1 String1, m), |
(desc : list (List1 String1, m), |
||
names : & |
names : &nodenames n0 >> nodenames n1, |
||
n : &size_t n0 >> size_t n1) |
n : &size_t n0 >> size_t n1) |
||
:<!wrt> #[n1 : int | n0 <= n1] |
:<!wrt> #[n1 : int | n0 <= n1] |
||
Line 824: | Line 824: | ||
nodename_number |
nodename_number |
||
{n : int} |
{n : int} |
||
(nodenames : |
(nodenames : nodenames n, |
||
name : String1) |
name : String1) |
||
:<> Option ( |
:<> Option (nodenum n) = |
||
let |
let |
||
fun |
fun |
||
loop {i : nat | i <= n} |
loop {i : nat | i <= n} |
||
.<n - i>. |
.<n - i>. |
||
(names : |
(names : nodenames (n - i), |
||
i : size_t i) |
i : size_t i) |
||
:<> Option ( |
:<> Option (nodenum n) = |
||
case+ names of |
case+ names of |
||
| NIL => None () |
| NIL => None () |
||
Line 849: | Line 849: | ||
fn |
fn |
||
add_edge {n : int} |
add_edge {n : int} |
||
(edges : |
(edges : edges n, |
||
from : |
from : nodenum n, |
||
to : |
to : nodenum n) |
||
:<!refwrt> void = |
:<!refwrt> void = |
||
(* This implementation does not store duplicate edges. *) |
(* This implementation does not store duplicate edges. *) |
||
let |
let |
||
val old_edges = edges[from] |
val old_edges = edges[from] |
||
implement list_find$pred< |
implement list_find$pred<nodenum n> s = (s = to) |
||
in |
in |
||
case+ list_find_opt< |
case+ list_find_opt<nodenum n> old_edges of |
||
| ~ None_vt () => edges[from] := to :: old_edges |
| ~ None_vt () => edges[from] := to :: old_edges |
||
| ~ Some_vt _ => () |
| ~ Some_vt _ => () |
||
Line 867: | Line 867: | ||
{n : int} |
{n : int} |
||
{m : int} |
{m : int} |
||
(edges : |
(edges : edges n, |
||
n : size_t n, |
n : size_t n, |
||
desc : |
desc : depdesc m, |
||
nodenames : |
nodenames : nodenames n) |
||
:<!refwrt> void = |
:<!refwrt> void = |
||
let |
let |
||
Line 893: | Line 893: | ||
{m1 : nat} |
{m1 : nat} |
||
.<m1>. |
.<m1>. |
||
(headnum : |
(headnum : nodenum n, |
||
lst : list (String1, m1)) |
lst : list (String1, m1)) |
||
:<!refwrt> void = |
:<!refwrt> void = |
||
Line 929: | Line 929: | ||
fn |
fn |
||
topodata_make |
|||
toposort_t_make |
|||
(desc : |
(desc : depdesc) |
||
:<!refwrt> [n : nat] |
:<!refwrt> [n : nat] |
||
@( |
@(topodata n, |
||
nodenames n) = |
|||
let |
let |
||
val @(nodenames, n) = collect_nodenames desc |
val @(nodenames, n) = collect_nodenames desc |
||
Line 939: | Line 939: | ||
prval [n : int] EQINT () = eqint_make_guint n |
prval [n : int] EQINT () = eqint_make_guint n |
||
val edges = arrayref_make_elt<List0 ( |
val edges = arrayref_make_elt<List0 (nodenum n)> (n, NIL) |
||
val () = fill_edges {n} (edges, n, desc, nodenames) |
val () = fill_edges {n} (edges, n, desc, nodenames) |
||
val tempmarks = |
val tempmarks = marks_make_elt (n, 0) |
||
and permmarks = |
and permmarks = marks_make_elt (n, 0) |
||
val topo = |
val topo = |
||
Line 963: | Line 963: | ||
*) |
*) |
||
(* What return values are made from. *) |
|||
datatype toporesult (a : t@ype, n : int) = |
|||
| {0 <= n} |
|||
Topo_SUCCESS (a, n) of list (a, n) |
|||
| Topo_CYCLE (a, n) of List1 a |
|||
typedef toporesult (a : t@ype) = [n : int] toporesult (a, n) |
|||
fn |
fn |
||
find_unmarked_node |
find_unmarked_node |
||
{n : int} |
{n : int} |
||
(topo : |
(topo : topodata n) |
||
:<!ref> Option ( |
:<!ref> Option (nodenum n) = |
||
let |
let |
||
val n = topo.n |
val n = topo.n |
||
Line 979: | Line 986: | ||
.<n - i>. |
.<n - i>. |
||
(i : size_t i) |
(i : size_t i) |
||
:<!ref> Option ( |
:<!ref> Option (nodenum n) = |
||
if i = n then |
if i = n then |
||
None () |
None () |
||
Line 992: | Line 999: | ||
fun |
fun |
||
visit {n : int} |
visit {n : int} |
||
(topo : |
(topo : topodata n, |
||
nodenum : |
nodenum : nodenum n, |
||
accum : List0 ( |
accum : List0 (nodenum n), |
||
path : List0 (nodenum n)) |
|||
: toporesult (nodenum n) = |
|||
(* Probably it is cumbersome to include a proof this routine |
(* Probably it is cumbersome to include a proof this routine |
||
terminates. Thus I will not try to |
terminates. Thus I will not try to write one. *) |
||
let |
let |
||
val |
val n = topo.n |
||
and edges = topo.edges |
|||
and tempmarks = topo.tempmarks |
and tempmarks = topo.tempmarks |
||
and permmarks = topo.permmarks |
and permmarks = topo.permmarks |
||
in |
in |
||
if permmarks[nodenum] = 1 then |
if permmarks[nodenum] = 1 then |
||
Topo_SUCCESS accum |
|||
else if tempmarks[nodenum] = 1 then |
else if tempmarks[nodenum] = 1 then |
||
let |
|||
val () = assertloc (isneqz path) |
|||
⚫ | |||
Topo_CYCLE (list_vt2t (reverse path)) |
|||
⚫ | |||
else |
else |
||
let |
let |
||
Line 1,013: | Line 1,026: | ||
{k : nat} |
{k : nat} |
||
.<k>. |
.<k>. |
||
(topo : |
(topo : topodata n, |
||
to_visit : list ( |
to_visit : list (nodenum n, k), |
||
accum : List0 ( |
accum : List0 (nodenum n), |
||
path : List0 (nodenum n)) |
|||
: toporesult (nodenum n) = |
|||
case+ to_visit of |
case+ to_visit of |
||
| NIL => |
| NIL => Topo_SUCCESS accum |
||
| node_to_visit :: tail => |
| node_to_visit :: tail => |
||
begin |
begin |
||
case+ visit (topo, node_to_visit, accum) of |
case+ visit (topo, node_to_visit, accum, path) of |
||
| |
| Topo_SUCCESS accum1 => |
||
recursive_visits (topo, tail, accum1, path) |
|||
| other => other |
|||
end |
end |
||
in |
in |
||
tempmarks[nodenum] := 1; |
tempmarks[nodenum] := 1; |
||
case+ recursive_visits (topo, edges[nodenum], accum |
case+ recursive_visits (topo, edges[nodenum], accum, |
||
nodenum :: path) of |
|||
| |
| Topo_SUCCESS accum1 => |
||
begin |
begin |
||
tempmarks[nodenum] := 0; |
tempmarks[nodenum] := 0; |
||
permmarks[nodenum] := 1; |
permmarks[nodenum] := 1; |
||
Topo_SUCCESS (nodenum :: accum1) |
|||
end |
end |
||
| other => other |
|||
end |
end |
||
end |
end |
||
Line 1,041: | Line 1,057: | ||
topological_sort |
topological_sort |
||
{n : int} |
{n : int} |
||
(topo : |
(topo : topodata n) |
||
: toporesult (nodenum n, n) = |
|||
(* I do not bother to try to restrict effects. *) |
|||
: Option (list (nodenum_t n, n)) = |
|||
let |
let |
||
prval () = lemma_arrayref_param (topo.edges) |
prval () = lemma_arrayref_param (topo.edges) |
||
fun |
fun |
||
sort (accum : List0 ( |
sort (accum : List0 (nodenum n)) |
||
: |
: toporesult (nodenum n, n) = |
||
case+ find_unmarked_node topo of |
case+ find_unmarked_node topo of |
||
| None () => |
| None () => |
||
Line 1,056: | Line 1,071: | ||
val () = assertloc (i2sz (length accum) = topo.n) |
val () = assertloc (i2sz (length accum) = topo.n) |
||
in |
in |
||
Topo_SUCCESS accum |
|||
end |
end |
||
| Some nodenum => |
| Some nodenum => |
||
begin |
begin |
||
case+ visit (topo, nodenum, accum) of |
case+ visit (topo, nodenum, accum, NIL) of |
||
| |
| Topo_SUCCESS accum1 => sort accum1 |
||
| |
| Topo_CYCLE cycle => Topo_CYCLE cycle |
||
end |
end |
||
Line 1,081: | Line 1,096: | ||
fn |
fn |
||
find_a_valid_order |
find_a_valid_order |
||
(desc : |
(desc : depdesc) |
||
⚫ | |||
(* I do not bother to try to restrict effects. *) |
|||
⚫ | |||
let |
let |
||
val @(topo, nodenames) = |
val @(topo, nodenames) = topodata_make desc |
||
in |
|||
⚫ | |||
⚫ | |||
| None () => None () |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
implement |
|||
list_map$fopr<nodenum n><String1> i = |
|||
nodenames_array[i] |
|||
⚫ | |||
macdef map = list_map<nodenum n><String1> |
|||
in |
|||
⚫ | |||
⚫ | |||
Topo_SUCCESS (list_vt2t (map valid_order)) |
|||
| Topo_CYCLE cycle => |
|||
Topo_CYCLE (list_vt2t (map cycle)) |
|||
end |
end |
||
Line 1,112: | Line 1,127: | ||
in |
in |
||
case+ find_a_valid_order desc of |
case+ find_a_valid_order desc of |
||
| Topo_SUCCESS valid_order => |
|||
| None () => println! "**** dependency loop ****" |
|||
println! (valid_order : List0 string) |
|||
| Topo_CYCLE cycle => |
|||
let |
|||
val last = list_last cycle |
|||
val cycl = list_vt2t (reverse (last :: cycle)) |
|||
⚫ | |||
println! ("COMPILATION CYCLE: ", cycl : List0 string) |
|||
end |
|||
end |
end |
||
Line 1,142: | Line 1,164: | ||
ieee, dware, dw05, dw06, dw07, gtech, dw01, dw04, dw02, std_cell_lib, synopsys, std, dw03, ramlib, des_system_lib |
ieee, dware, dw05, dw06, dw07, gtech, dw01, dw04, dw02, std_cell_lib, synopsys, std, dw03, ramlib, des_system_lib |
||
</pre> |
</pre> |
||
AND ... |
|||
Data fed to standard input: |
Data fed to standard input: |
||
<pre> |
<pre> |
||
a b; b d; d a e; e a; |
|||
des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee; |
|||
dw01 ieee dw01 dware gtech dw04; |
|||
dw02 ieee dw02 dware; |
|||
dw03 std synopsys dware dw03 dw02 dw01 ieee gtech; |
|||
dw04 dw04 ieee dw01 dware gtech; |
|||
dw05 dw05 ieee dware; |
|||
dw06 dw06 ieee dware; |
|||
dw07 ieee dware; |
|||
dware ieee dware; |
|||
gtech ieee gtech; |
|||
ramlib std ieee; |
|||
std_cell_lib ieee std_cell_lib; |
|||
synopsys; |
|||
</pre> |
</pre> |
||
Data from standard output: |
Data from standard output: |
||
<pre> |
<pre> |
||
COMPILATION CYCLE: b, d, e, a, b |
|||
**** dependency loop **** |
|||
</pre> |
</pre> |
||
''Note: I plan to enhance the function to return information about the cyclic dependency, rather than simply "None()".'' |
|||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |