Dijkstra's algorithm: Difference between revisions

Line 755:
 
This implementation is based on suggestions from
[https://en.wikipedia.org/w/index.php?title=Dijkstra%27s_algorithm&oldid=1117533081#Using_a_priority_queue a Wikipedia article about Dijkstra's algorithm], although I use a different method to determine whether a queue entry is obsolete.
 
''Note: Currently I do not prove termination ofthat the algorithm terminates.''
 
<syntaxhighlight lang="ats">
Line 1,006:
fn
fprint_vertex_path
{n : int}
(outf : FILEref,
vertex_arr : arrayref (string, n),
path : List ([i : nat | i < n] size_t i)),
cost_opt : Option flt,
cost_column_no : size_t)
: void =
let
Line 1,015 ⟶ 1,017:
loop {m : nat}
.<m>.
(path : list ([i : nat | i < n] size_t i, m)),
: void =column_no : size_t)
: size_t =
case+ path of
| NIL => ()column_no
| i :: NIL => fprint! (outf, vertex_arr[i])
begin
fprint! (outf, vertex_arr[i]);
column_no + strlen vertex_arr[i]
end
| i :: tail =>
begin
fprint! (outf, vertex_arr[i], " -> ");
loop (tail, column_no + strlen vertex_arr[i] + i2sz 4)
end
 
prval () = lemma_list_param path
val column_no = loop (path, i2sz 1)
in
loopcase+ pathcost_opt of
| None () => ()
| Some cost =>
let
var i : size_t = column_no
in
while (i < cost_column_no)
begin
fprint! (outf, " ");
i := succ i
end;
fprint! (outf, "(cost = ", cost, ")")
end
end
 
Line 1,042 ⟶ 1,062:
source : size_t source)
(* Returns total-costs and previous-hops arrays. *)
:<!refwrt,!ntm> @(arrayref (flt, n),
arrayref ([i : nat | i <= n] size_t i, n)) =
let
prval () = lemma_matrixref_param adj_matrix
Line 1,062 ⟶ 1,082:
 
val active = arrayref_make_elt<bool> (n, true)
var num_active : [i : nat | i <= n] size_t i = n
 
fun
Line 1,076 ⟶ 1,097:
 
fun
extract_min
main_loop (pq : &pqueue_t >> _)
{m0 : nat}
:<!refwrt,!ntm> void =
if ~pqueue_is_empty pq then .<m0>.
(pq : &pqueue_t m0 >> pqueue_t m1)
:<!refwrt> #[m1 : nat | m1 <= m0]
Option @(flt, defined_index_t) =
if pqueue_is_empty pq then
None ()
else
let
val @(priority, uvertex) =
pqueue_extract_min<flt><defined_index_t> pq
in
if ~active[vertex] then
(* Ignore any queue entries that might raise the cost. *)
if priority >extract_min cost[u] thenpq
main_loop pq
else
letSome @(priority, vertex)
end
val () = active[u] := false
 
fun
main_loop {num_active0 : nat | num_active0 <= n}
loop_over_neighbors
{v : nat | v .<= n}num_active0>.
(pq : .<n&pqueue_t - v>.> pqueue_t,
(pqnum_active : &pqueue_tsize_t num_active0 >> pqueue_t,size_t num_active1)
:<!refwrt> #[num_active1 : nat | num_active1 <= num_active0]
v : size_t v)
:<!refwrt> void =
if num_active <> i2sz if v = n0 then
case+ extract_min pq ()of
| None () else if ~active[v] then=>
(* This branch should never be loop_over_neighbors (pqreached, succbut v)the
corresponding sanity check elseis done further below. Thus
the proof of termination of letthis loop does not depend on
an exception. *)
val alternative = cost[u] + adj_matrix[u, n, v]
in()
| Some @(priority, u) =>
if alternative < cost[v] then
beginlet
val () = costactive[vu] := alternative;false
and () = prev[v]num_active := u;pred num_active
 
fun
(* Rather than lower the priority of v, this
loop_over_neighbors
implementation inserts a new entry for v
{v : nat | v and<= ignores any queue entries whosen}
.<n - priority exceeds cost[v]>. *)
(pq : &pqueue_t pqueue_insert<flt><defined_index_t> pqueue_t,
v : (pq, alternative,size_t v)
:<!refwrt> void end;=
if v = n loop_over_neighbors (pq, succ v)then
end()
in else if ~active[v] then
loop_over_neighbors (pq, i2szsucc 0v);
main_loop pqelse
end; let
val alternative = cost[u] + adj_matrix[u, n, v]
end
in
if alternative < cost[v] then
begin
cost[v] := alternative;
prev[v] := u;
 
(* Rather than lower the priority of v, this
implementation inserts a new entry for v and
ignores obsolete queue entries. Queue entries
are obsolete if the vertex's entry in the
"active" array is false. *)
 
pqueue_insert<flt><defined_index_t>
(pq, alternative, v)
end;
loop_over_neighbors (pq, succ v)
end
in
loop_over_neighbors (pq, i2sz 0);
main_loop {num_active0 - 1} (pq, num_active)
end
 
val () = fill_pq (pq, i2sz 0)
val () = main_loop {n} (pq, num_active)
 
(* Sanity check. *)
val- true = iseqz num_active
in
@(cost, prev)
Line 1,199 ⟶ 1,249:
val- Some path_a_to_e = least_cost_path {n} (a, prev, n, e)
val- Some path_a_to_f = least_cost_path {n} (a, prev, n, f)
 
var u : [i : nat | i <= n] size_t i
val cost_column_no = i2sz 20
in
println! ("The requested paths:");
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_e);
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_e,
println! (" (cost = ", cost[e], ")");
Some cost[e], cost_column_no);
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_f);
println! (" (cost = ", cost[f], ")");
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_f,
Some cost[f], cost_column_no);
println! ();
println! ();
println! ("All paths (in no particular order):");
for (u := i2sz 0; u <> n; u := succ u)
case+ least_cost_path {n} (a, prev, n, u) of
| None () =>
println! ("There is no path from ", vertex_arr[a], " to ",
vertex_arr[u], ".")
| Some path =>
begin
fprint_vertex_path (stdout_ref, vertex_arr, path,
Some cost[u], cost_column_no);
println! ()
end
end
 
Line 1,211 ⟶ 1,280:
{{out}}
<pre>$ patscc -DATS_MEMALLOC_GCBDW dijkstra-algorithm.dats -lgc && ./a.out
The requested paths:
a -> c -> d -> e (cost = 26.000000)
a -> c -> f d -> e (cost = 1126.000000)</pre>
a -> c -> f (cost = 11.000000)
 
All paths (in no particular order):
a -> c -> d -> e (cost = 26.000000)
a -> c -> d (cost = 20.000000)
a -> c -> f (cost = 11.000000)
a -> c (cost = 9.000000)
a -> b (cost = 7.000000)
a (cost = 0.000000)
</pre>
 
=={{header|AutoHotkey}}==
1,448

edits