From d3b8b2b48b37b6ffd4b8404a3e96cd961e7c1143 Mon Sep 17 00:00:00 2001 From: Paolo Donadeo Date: Sat, 29 Jul 2017 17:12:16 +0200 Subject: [PATCH] Single-Source Shortest Paths Dijkstra's algorithm --- src/pack.ml | 1 + src/path.ml | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/path.mli | 31 +++++++++++++++ 3 files changed, 140 insertions(+) diff --git a/src/pack.ml b/src/pack.ml index 3f334038..7b9058cd 100644 --- a/src/pack.ml +++ b/src/pack.ml @@ -53,6 +53,7 @@ struct end include Path.Dijkstra(G)(W) + include Path.SSSP_Dijkstra(G)(W) include Path.Johnson(G)(W) module BF = Path.BellmanFord(G)(W) diff --git a/src/path.ml b/src/path.ml index fb5e0cdb..7844b2c6 100644 --- a/src/path.ml +++ b/src/path.ml @@ -100,6 +100,114 @@ struct end +module type G_SSSP = sig + include G + + val find_edge : t -> V.t -> V.t -> E.t +end + +module SSSP_Dijkstra + (G: G_SSSP) + (W: Sig.WEIGHT with type edge = G.E.t) = +struct + + open G.E + + module H = Hashtbl.Make(G.V) + + module Elt = struct + type t = W.t * G.V.t + + (* weights are compared first, and minimal weights come first in the + queue *) + let compare (w1,v1) (w2,v2) = + let cw = W.compare w2 w1 in + if cw != 0 then cw else G.V.compare v1 v2 + end + + module PQ = Heap.Imperative(Elt) + + let all_shortest_paths (g : G.t) (source : G.V.t) : (G.V.t * G.V.t list list * W.t) list = + let visited = H.create 97 in + let pred = H.create 97 in + let dist = H.create 97 in + let q = PQ.create 17 in + + let update ?(replace=true) u v e dv' = + H.replace dist v dv'; + if replace + then H.replace pred v (u, e) + else H.add pred v (u, e); + PQ.add q (dv', v) + in + + let relax u v e = + let w_uv = W.weight e in + let du = H.find dist u in + try begin + let dv' = W.add du w_uv in + let comparison = W.compare dv' (H.find dist v) in + match comparison with + | c when c < 0 -> update u v e dv' + | 0 -> update ~replace:false u v e dv' + | _ -> () (* makes the complier happy *) + end with Not_found -> update u v e (W.add du w_uv) in + + let rec recreate_path (last_v : G.V.t) (path : G.V.t list) : G.V.t list list = + let my_pred = H.find_all pred last_v in + if List.length my_pred = 0 + then [path] + else + List.fold_left (fun acc (u, _) -> + let new_path = recreate_path u (u::path) in + List.rev_append new_path acc + ) [] my_pred in + + let get_result () = + H.remove dist source; + H.fold (fun v d a -> + (v, recreate_path v [v], d)::a + ) dist [] |> List.rev in + + let rec loop () = + if PQ.is_empty q then get_result () + else + let (_, u) = PQ.pop_maximum q in + if not (H.mem visited u) then begin + H.add visited u (); + G.iter_succ_e + (fun e -> + let v = dst e in + if not (H.mem visited v) + then relax u v e) + g u + end; + loop () in + + PQ.add q (W.zero, source); + H.add dist source W.zero; + loop () + + let all_shortest_paths_e (g : G.t) (source : G.V.t) : (G.V.t * G.E.t list list * W.t) list = + let fold_by_couple f acc lst = + let rec inner_aux f acc lst = + match lst with + | p0::((p1::_) as l) -> inner_aux f (f p0 p1 acc) l + | [_] -> acc + | [] -> failwith "Impossible pattern!" in + inner_aux f acc lst in + + List.rev_map (fun (dest, paths, w) -> + let paths' = List.map (fun path -> + fold_by_couple (fun u v acc -> + (G.find_edge g u v)::acc + ) [] path |> List.rev + ) paths in + (dest, paths', w) + ) (all_shortest_paths g source) |> List.rev + +end;; + (* The following module is a contribution of Yuto Takei (University of Tokyo) *) module BellmanFord diff --git a/src/path.mli b/src/path.mli index 5b1e74ac..9219c305 100644 --- a/src/path.mli +++ b/src/path.mli @@ -55,6 +55,37 @@ sig end +(** Minimal graph signature for SSSP Dijkstra's algorithm. + Sub-signature of {!Sig.G}. *) +module type G_SSSP = sig + include G + + val find_edge : t -> V.t -> V.t -> E.t +end + +module SSSP_Dijkstra + (G: G_SSSP) + (W: Sig.WEIGHT with type edge = G.E.t) : +sig + + val all_shortest_paths : G.t -> G.V.t -> (G.V.t * G.V.t list list * W.t) list + (** [shortest_path g source] computes the all the shortest paths from + vertex [source] to all other vertices in graph [g]. The paths are + returned as the list of the destination, a list of equal length + paths (traversed vertices), together with the total length of the + paths. + + Complexity: at most O((V+E)log(V)) *) + + val all_shortest_paths_e : G.t -> G.V.t -> (G.V.t * G.E.t list list * W.t) list + (** [shortest_path_e g source] computes the all the shortest paths from + vertex [source] to all other vertices in graph [g]. The paths are + returned as the list of the destination, a list of equal length + paths (followed edges), together with the total length of the paths. + + Complexity: at most O((V+E)log(V)) *) +end + (* The following module is a contribution of Yuto Takei (University of Tokyo) *) module BellmanFord