assignment
This commit is contained in:
4 files changed
+299
No files matched your search
@@ -0,0 +1,155 @@
|
||||
open Digraph
|
||||
|
||||
(** [read_file src] returns all lines from the file named [src]
|
||||
* in the same order they appear in the file.
|
||||
*)
|
||||
let read_file src =
|
||||
let ic = open_in src in
|
||||
let rec read_file_line acc =
|
||||
try
|
||||
let line = input_line ic in
|
||||
read_file_line (line :: acc)
|
||||
with
|
||||
| End_of_file ->
|
||||
close_in ic;
|
||||
List.rev acc
|
||||
in
|
||||
read_file_line []
|
||||
|
||||
(** [parse_line line] tries to parse [line] as an edge.
|
||||
* It uses only the first 3 words and ignores any extra words.
|
||||
* It returns [None] if [line] does not contain 2 vertices followed
|
||||
* by an integer edge length.
|
||||
*)
|
||||
let parse_line line =
|
||||
let parts = String.split_on_char ' ' line in
|
||||
let filtered_parts = List.filter (fun x -> x <> "") parts in
|
||||
match filtered_parts with
|
||||
| src :: dst :: len_str :: _ ->
|
||||
(
|
||||
try
|
||||
let len = int_of_string len_str in
|
||||
Some (src, dst, len)
|
||||
with
|
||||
| Failure _ -> None
|
||||
)
|
||||
| _ -> None
|
||||
|
||||
(** [read_data src] reads graph data from the file named [src]
|
||||
* and returns the resulting digraph.
|
||||
* Lines that do not match the expected format are skipped.
|
||||
* It may raise [Invalid] if a parsed edge is invalid or duplicated.
|
||||
*)
|
||||
let read_data src =
|
||||
let lines = read_file src in
|
||||
let edge_list =
|
||||
List.fold_right
|
||||
(fun line acc ->
|
||||
match parse_line line with
|
||||
| Some edge -> edge :: acc
|
||||
| None -> acc)
|
||||
lines
|
||||
[]
|
||||
in
|
||||
Digraph.of_edges edge_list
|
||||
|
||||
(** [update_distance vertex new_dist dist_list] returns a new distance
|
||||
* list where [vertex] has distance [new_dist].
|
||||
* If [vertex] is not already present, it is added.
|
||||
*)
|
||||
let rec update_distance vertex new_dist dist_list =
|
||||
match dist_list with
|
||||
| [] -> [(vertex, new_dist)]
|
||||
| (v, d) :: rest ->
|
||||
if v = vertex then
|
||||
(v, new_dist) :: rest
|
||||
else
|
||||
(v, d) :: update_distance vertex new_dist rest
|
||||
|
||||
(** [find_min_vertex dist_list unvisited] returns [Some (v, d)] where [v]
|
||||
* is the unvisited vertex with the smallest distance in [dist_list].
|
||||
* It returns [None] if no unvisited vertex remains.
|
||||
*)
|
||||
let find_min_vertex dist_list unvisited =
|
||||
List.fold_left
|
||||
(fun acc (v, d) ->
|
||||
if not (List.mem v unvisited) then
|
||||
acc
|
||||
else
|
||||
match acc with
|
||||
| None -> Some (v, d)
|
||||
| Some (_, d_min) ->
|
||||
if d < d_min then
|
||||
Some (v, d)
|
||||
else
|
||||
acc)
|
||||
None
|
||||
dist_list
|
||||
|
||||
(** [update_predecessor vertex pred pred_list] returns a new predecessor
|
||||
* list where [vertex] has predecessor [pred].
|
||||
* If [vertex] is not already present, it is added.
|
||||
*)
|
||||
let rec update_predecessor vertex pred pred_list =
|
||||
match pred_list with
|
||||
| [] -> [(vertex, Some pred)]
|
||||
| (v, p) :: rest ->
|
||||
if v = vertex then
|
||||
(v, Some pred) :: rest
|
||||
else
|
||||
(v, p) :: update_predecessor vertex pred rest
|
||||
|
||||
(** [construct_path prev_list v acc] builds the path ending at [v]
|
||||
* by following predecessors in [prev_list].
|
||||
* The list [acc] stores the path built so far.
|
||||
*)
|
||||
let rec construct_path prev_list v acc =
|
||||
match List.assoc v prev_list with
|
||||
| None -> acc
|
||||
| Some u -> construct_path prev_list u (u :: acc)
|
||||
|
||||
(** [shortest_path src dst graph] returns a pair containing the total
|
||||
* length of a shortest path from [src] to [dst] in [graph], and the
|
||||
* path itself as a list of vertices from [src] to [dst].
|
||||
* It raises [Failure] if no path exists or if either vertex is missing.
|
||||
*)
|
||||
let shortest_path src dst graph =
|
||||
let verts = Digraph.vertices graph in
|
||||
if not (List.mem src verts) || not (List.mem dst verts) then
|
||||
failwith "No path found"
|
||||
else
|
||||
let dist_list =
|
||||
List.map (fun v -> (v, if v = src then 0 else max_int)) verts
|
||||
in
|
||||
let prev_list =
|
||||
List.map (fun v -> (v, None)) verts
|
||||
in
|
||||
let rec dijkstra_helper dist_list prev_list unvisited =
|
||||
match find_min_vertex dist_list unvisited with
|
||||
| None -> failwith "No path found"
|
||||
| Some (u, d_u) ->
|
||||
if d_u = max_int then
|
||||
failwith "No path found"
|
||||
else if u = dst then
|
||||
let path = construct_path prev_list u [u] in
|
||||
(d_u, path)
|
||||
else
|
||||
let neighbors_list = Digraph.neighbors u graph in
|
||||
let (dist_list', prev_list') =
|
||||
List.fold_left
|
||||
(fun (d_acc, p_acc) (v, weight) ->
|
||||
let d_v = List.assoc v d_acc in
|
||||
let alt = d_u + weight in
|
||||
if alt < d_v then
|
||||
let d_acc' = update_distance v alt d_acc in
|
||||
let p_acc' = update_predecessor v u p_acc in
|
||||
(d_acc', p_acc')
|
||||
else
|
||||
(d_acc, p_acc))
|
||||
(dist_list, prev_list)
|
||||
neighbors_list
|
||||
in
|
||||
let unvisited' = List.filter (fun x -> x <> u) unvisited in
|
||||
dijkstra_helper dist_list' prev_list' unvisited'
|
||||
in
|
||||
dijkstra_helper dist_list prev_list verts
|
||||
Reference in new issue
Block a user