First Commit
This commit is contained in:
commit
9d4e63d467
12 changed files with 498 additions and 0 deletions
20
Makefile
Normal file
20
Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
build:
|
||||
@echo "\n==== COMPILING ====\n"
|
||||
ocamlbuild ftest.native
|
||||
|
||||
format:
|
||||
ocp-indent --inplace src/*
|
||||
|
||||
edit:
|
||||
code . -n
|
||||
|
||||
demo: build
|
||||
@echo "\n==== EXECUTING ====\n"
|
||||
./ftest.native graphs/graph1 1 2 outfile
|
||||
@echo "\n==== RESULT ==== (content of outfile) \n"
|
||||
@cat outfile
|
||||
|
||||
clean:
|
||||
-rm -rf _build/
|
||||
-rm ftest.native
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
Base project for Ocaml project on Ford-Fulkerson. This project contains some simple configuration files to facilitate editing Ocaml in VSCode.
|
||||
|
||||
To use, you should install the *OCaml* extension in VSCode. Other extensions might work as well but make sure there is only one installed.
|
||||
Then open VSCode in the root directory of this repository (command line: `code path/to/ocaml-maxflow-project`).
|
||||
|
||||
Features :
|
||||
- full compilation as VSCode build task (Ctrl+Shift+b)
|
||||
- highlights of compilation errors as you type
|
||||
- code completion
|
||||
- automatic indentation on file save
|
||||
|
||||
|
||||
A makefile provides some useful commands:
|
||||
- `make build` to compile. This creates an ftest.native executable
|
||||
- `make demo` to run the `ftest` program with some arguments
|
||||
- `make format` to indent the entire project
|
||||
- `make edit` to open the project in VSCode
|
||||
- `make clean` to remove build artifacts
|
||||
|
||||
In case of trouble with the VSCode extension (e.g. the project does not build, there are strange mistakes), a common workaround is to (1) close vscode, (2) `make clean`, (3) `make build` and (4) reopen vscode (`make edit`).
|
||||
|
3
_tags
Normal file
3
_tags
Normal file
|
@ -0,0 +1,3 @@
|
|||
<src/**>: include
|
||||
|
||||
|
24
graphs/graph1
Normal file
24
graphs/graph1
Normal file
|
@ -0,0 +1,24 @@
|
|||
%% Test graph #1
|
||||
|
||||
%% Nodes
|
||||
|
||||
n 88 209 % This is node #0, with its coordinates (which are not used by the algorithms).
|
||||
n 408 183
|
||||
n 269 491
|
||||
n 261 297
|
||||
n 401 394
|
||||
n 535 294 % This is node #5.
|
||||
|
||||
|
||||
%% Edges
|
||||
|
||||
e 3 1 11 % An edge from 3 to 1, labeled "11".
|
||||
e 3 2 2
|
||||
e 1 5 21
|
||||
e 4 5 14
|
||||
e 1 4 1
|
||||
e 0 1 7
|
||||
e 0 3 10
|
||||
e 3 4 5
|
||||
e 2 4 12
|
||||
e 0 2 8
|
106
graphs/graph1.svg
Normal file
106
graphs/graph1.svg
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [
|
||||
<!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Generated by dot version 2.7.20060111.0540 (Fri Sep 3 08:16:42 UTC 2010)
|
||||
For user: (lebotlan) D. Le Botlan,,, -->
|
||||
<!-- Title: finite_state_machine Pages: 1 -->
|
||||
<svg width="689px" height="302px"
|
||||
viewBox = "0 0 517 227"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" style="font-family:Times-Roman;font-size:14.00;">
|
||||
<title>finite_state_machine</title>
|
||||
<polygon style="fill:white;stroke:white;" points="0,227 0,-11 528,-11 528,227 0,227"/>
|
||||
<!-- 0 -->
|
||||
<g id="node1" class="node"><title>0</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="29" cy="112" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="29" y="119">0</text>
|
||||
</g>
|
||||
<!-- 2 -->
|
||||
<g id="node3" class="node"><title>2</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="259" cy="43" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="259" y="50">2</text>
|
||||
</g>
|
||||
<!-- 0->2 -->
|
||||
<g id="edge2" class="edge"><title>0->2</title>
|
||||
<path style="fill:none;stroke:black;" d="M51,100C59,95 68,90 77,86 127,64 140,59 192,48 201,47 212,46 221,44"/>
|
||||
<polygon style="fill:black;stroke:black;" points="221,39 235,44 221,48 221,39"/>
|
||||
<text text-anchor="middle" x="144" y="52">8</text>
|
||||
</g>
|
||||
<!-- 3 -->
|
||||
<g id="node5" class="node"><title>3</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="144" cy="112" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="144" y="119">3</text>
|
||||
</g>
|
||||
<!-- 0->3 -->
|
||||
<g id="edge4" class="edge"><title>0->3</title>
|
||||
<path style="fill:none;stroke:black;" d="M53,112C69,112 89,112 107,112"/>
|
||||
<polygon style="fill:black;stroke:black;" points="107,107 120,112 107,116 107,107"/>
|
||||
<text text-anchor="middle" x="87" y="108">10</text>
|
||||
</g>
|
||||
<!-- 1 -->
|
||||
<g id="node7" class="node"><title>1</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="259" cy="191" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="259" y="198">1</text>
|
||||
</g>
|
||||
<!-- 0->1 -->
|
||||
<g id="edge6" class="edge"><title>0->1</title>
|
||||
<path style="fill:none;stroke:black;" d="M48,127C65,142 93,160 120,170 153,182 192,187 221,188"/>
|
||||
<polygon style="fill:black;stroke:black;" points="221,184 235,190 221,192 221,184"/>
|
||||
<text text-anchor="middle" x="144" y="162">7</text>
|
||||
</g>
|
||||
<!-- 4 -->
|
||||
<g id="node9" class="node"><title>4</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="373" cy="120" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="373" y="127">4</text>
|
||||
</g>
|
||||
<!-- 2->4 -->
|
||||
<g id="edge8" class="edge"><title>2->4</title>
|
||||
<path style="fill:none;stroke:black;" d="M279,56C296,68 321,86 343,99"/>
|
||||
<polygon style="fill:black;stroke:black;" points="345,95 353,107 340,103 345,95"/>
|
||||
<text text-anchor="middle" x="316" y="72">12</text>
|
||||
</g>
|
||||
<!-- 3->2 -->
|
||||
<g id="edge12" class="edge"><title>3->2</title>
|
||||
<path style="fill:none;stroke:black;" d="M165,99C183,90 207,75 225,63"/>
|
||||
<polygon style="fill:black;stroke:black;" points="224,59 237,55 229,66 224,59"/>
|
||||
<text text-anchor="middle" x="201" y="71">2</text>
|
||||
</g>
|
||||
<!-- 3->1 -->
|
||||
<g id="edge14" class="edge"><title>3->1</title>
|
||||
<path style="fill:none;stroke:black;" d="M161,128C171,136 181,146 192,152 203,159 215,167 225,172"/>
|
||||
<polygon style="fill:black;stroke:black;" points="228,168 237,179 224,176 228,168"/>
|
||||
<text text-anchor="middle" x="201" y="148">11</text>
|
||||
</g>
|
||||
<!-- 3->4 -->
|
||||
<g id="edge10" class="edge"><title>3->4</title>
|
||||
<path style="fill:none;stroke:black;" d="M168,114C208,115 288,118 336,119"/>
|
||||
<polygon style="fill:black;stroke:black;" points="336,114 349,119 336,123 336,114"/>
|
||||
<text text-anchor="middle" x="259" y="114">5</text>
|
||||
</g>
|
||||
<!-- 1->4 -->
|
||||
<g id="edge16" class="edge"><title>1->4</title>
|
||||
<path style="fill:none;stroke:black;" d="M280,179C293,171 311,162 325,152 331,150 336,146 343,142"/>
|
||||
<polygon style="fill:black;stroke:black;" points="340,138 353,135 344,146 340,138"/>
|
||||
<text text-anchor="middle" x="316" y="148">1</text>
|
||||
</g>
|
||||
<!-- 5 -->
|
||||
<g id="node15" class="node"><title>5</title>
|
||||
<ellipse style="fill:none;stroke:black;" cx="488" cy="168" rx="18" ry="18"/>
|
||||
<text text-anchor="middle" x="488" y="175">5</text>
|
||||
</g>
|
||||
<!-- 1->5 -->
|
||||
<g id="edge18" class="edge"><title>1->5</title>
|
||||
<path style="fill:none;stroke:black;" d="M283,188C311,186 357,182 397,178 415,175 433,174 451,172"/>
|
||||
<polygon style="fill:black;stroke:black;" points="451,168 464,171 451,176 451,168"/>
|
||||
<text text-anchor="middle" x="373" y="174">21</text>
|
||||
</g>
|
||||
<!-- 4->5 -->
|
||||
<g id="edge20" class="edge"><title>4->5</title>
|
||||
<path style="fill:none;stroke:black;" d="M396,130C412,138 435,147 453,154"/>
|
||||
<polygon style="fill:black;stroke:black;" points="455,150 465,159 451,158 455,150"/>
|
||||
<text text-anchor="middle" x="431" y="138">14</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
21
graphs/graph1.txt
Normal file
21
graphs/graph1.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
% This is a graph.
|
||||
|
||||
n 20 300 0
|
||||
n 200 300 1
|
||||
n 200 200 2
|
||||
n 200 400 3
|
||||
n 380 300 4
|
||||
n 380 200 5
|
||||
|
||||
e 0 2 0 8
|
||||
e 0 3 1 10
|
||||
e 0 1 2 7
|
||||
e 2 4 3 12
|
||||
e 3 4 4 5
|
||||
e 3 2 5 2
|
||||
e 3 1 6 11
|
||||
e 1 4 7 1
|
||||
e 1 5 8 21
|
||||
e 4 5 9 14
|
||||
|
||||
% End of graph
|
37
graphs/graph2.txt
Normal file
37
graphs/graph2.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
% This is a graph.
|
||||
|
||||
n 20 300 0
|
||||
n 200 300 1
|
||||
n 200 200 2
|
||||
n 200 400 3
|
||||
n 380 300 4
|
||||
n 380 200 5
|
||||
n 380 400 6
|
||||
n 380 100 7
|
||||
n 380 500 8
|
||||
n 560 300 9
|
||||
n 560 200 10
|
||||
n 560 400 11
|
||||
n 560 100 12
|
||||
|
||||
e 0 3 0 2
|
||||
e 0 2 1 2
|
||||
e 0 1 2 4
|
||||
e 1 4 3 2
|
||||
e 1 6 4 2
|
||||
e 1 5 5 2
|
||||
e 4 10 6 2
|
||||
e 2 5 7 2
|
||||
e 10 12 8 6
|
||||
e 3 6 9 2
|
||||
e 3 8 10 2
|
||||
e 6 9 11 2
|
||||
e 8 11 12 2
|
||||
e 11 9 13 2
|
||||
e 9 10 14 4
|
||||
e 5 10 15 1
|
||||
e 5 7 16 1
|
||||
e 7 12 17 2
|
||||
e 7 10 18 1
|
||||
|
||||
% End of graph
|
35
src/ftest.ml
Normal file
35
src/ftest.ml
Normal file
|
@ -0,0 +1,35 @@
|
|||
open Gfile
|
||||
|
||||
let () =
|
||||
|
||||
(* Check the number of command-line arguments *)
|
||||
if Array.length Sys.argv <> 5 then
|
||||
begin
|
||||
Printf.printf
|
||||
"\n ✻ Usage: %s infile source sink outfile\n\n%s%!" Sys.argv.(0)
|
||||
(" 🟄 infile : input file containing a graph\n" ^
|
||||
" 🟄 source : identifier of the source vertex (used by the ford-fulkerson algorithm)\n" ^
|
||||
" 🟄 sink : identifier of the sink vertex (ditto)\n" ^
|
||||
" 🟄 outfile : output file in which the result should be written.\n\n") ;
|
||||
exit 0
|
||||
end ;
|
||||
|
||||
|
||||
(* Arguments are : infile(1) source-id(2) sink-id(3) outfile(4) *)
|
||||
|
||||
let infile = Sys.argv.(1)
|
||||
and outfile = Sys.argv.(4)
|
||||
|
||||
(* These command-line arguments are not used for the moment. *)
|
||||
and _source = int_of_string Sys.argv.(2)
|
||||
and _sink = int_of_string Sys.argv.(3)
|
||||
in
|
||||
|
||||
(* Open file *)
|
||||
let graph = from_file infile in
|
||||
|
||||
(* Rewrite the graph that has been read. *)
|
||||
let () = write_file outfile graph in
|
||||
|
||||
()
|
||||
|
101
src/gfile.ml
Normal file
101
src/gfile.ml
Normal file
|
@ -0,0 +1,101 @@
|
|||
open Graph
|
||||
open Printf
|
||||
|
||||
type path = string
|
||||
|
||||
(* Format of text files:
|
||||
% This is a comment
|
||||
|
||||
% A node with its coordinates (which are not used).
|
||||
n 88.8 209.7
|
||||
n 408.9 183.0
|
||||
|
||||
% The first node has id 0, the next is 1, and so on.
|
||||
|
||||
% Edges: e source dest label
|
||||
e 3 1 11
|
||||
e 0 2 8
|
||||
|
||||
*)
|
||||
|
||||
let write_file path graph =
|
||||
|
||||
(* Open a write-file. *)
|
||||
let ff = open_out path in
|
||||
|
||||
(* Write in this file. *)
|
||||
fprintf ff "%% This is a graph.\n\n" ;
|
||||
|
||||
(* Write all nodes (with fake coordinates) *)
|
||||
n_iter_sorted graph (fun id -> fprintf ff "n %.1f 1.0\n" (float_of_int id)) ;
|
||||
fprintf ff "\n" ;
|
||||
|
||||
(* Write all arcs *)
|
||||
e_iter graph (fun id1 id2 lbl -> fprintf ff "e %d %d %s\n" id1 id2 lbl) ;
|
||||
|
||||
fprintf ff "\n%% End of graph\n" ;
|
||||
|
||||
close_out ff ;
|
||||
()
|
||||
|
||||
(* Reads a line with a node. *)
|
||||
let read_node id graph line =
|
||||
try Scanf.sscanf line "n %f %f" (fun _ _ -> new_node graph id)
|
||||
with e ->
|
||||
Printf.printf "Cannot read node in line - %s:\n%s\n%!" (Printexc.to_string e) line ;
|
||||
failwith "from_file"
|
||||
|
||||
(* Ensure that the given node exists in the graph. If not, create it.
|
||||
* (Necessary because the website we use to create online graphs does not generate correct files when some nodes have been deleted.) *)
|
||||
let ensure graph id = if node_exists graph id then graph else new_node graph id
|
||||
|
||||
(* Reads a line with an arc. *)
|
||||
let read_arc graph line =
|
||||
try Scanf.sscanf line "e %d %d %s"
|
||||
(fun id1 id2 label -> new_arc (ensure (ensure graph id1) id2) id1 id2 label)
|
||||
with e ->
|
||||
Printf.printf "Cannot read arc in line - %s:\n%s\n%!" (Printexc.to_string e) line ;
|
||||
failwith "from_file"
|
||||
|
||||
(* Reads a comment or fail. *)
|
||||
let read_comment graph line =
|
||||
try Scanf.sscanf line " %%" graph
|
||||
with _ ->
|
||||
Printf.printf "Unknown line:\n%s\n%!" line ;
|
||||
failwith "from_file"
|
||||
|
||||
let from_file path =
|
||||
|
||||
let infile = open_in path in
|
||||
|
||||
(* Read all lines until end of file.
|
||||
* n is the current node counter. *)
|
||||
let rec loop n graph =
|
||||
try
|
||||
let line = input_line infile in
|
||||
|
||||
(* Remove leading and trailing spaces. *)
|
||||
let line = String.trim line in
|
||||
|
||||
let (n2, graph2) =
|
||||
(* Ignore empty lines *)
|
||||
if line = "" then (n, graph)
|
||||
|
||||
(* The first character of a line determines its content : n or e. *)
|
||||
else match line.[0] with
|
||||
| 'n' -> (n+1, read_node n graph line)
|
||||
| 'e' -> (n, read_arc graph line)
|
||||
|
||||
(* It should be a comment, otherwise we complain. *)
|
||||
| _ -> (n, read_comment graph line)
|
||||
in
|
||||
loop n2 graph2
|
||||
|
||||
with End_of_file -> graph (* Done *)
|
||||
in
|
||||
|
||||
let final_graph = loop 0 empty_graph in
|
||||
|
||||
close_in infile ;
|
||||
final_graph
|
||||
|
18
src/gfile.mli
Normal file
18
src/gfile.mli
Normal file
|
@ -0,0 +1,18 @@
|
|||
(* Read a graph from a file,
|
||||
* Write a graph to a file. *)
|
||||
|
||||
open Graph
|
||||
|
||||
type path = string
|
||||
|
||||
(* Values are read as strings. *)
|
||||
val from_file: path -> string graph
|
||||
|
||||
(* Similarly, we write only a string graph.
|
||||
* If necessary, use gmap (to be written by you) to prepare the input graph. *)
|
||||
val write_file: path -> string graph -> unit
|
||||
|
||||
|
||||
(* The format of files is compatible with the files generated by:
|
||||
https://algorithms.discrete.ma.tum.de/graph-algorithms/flow-ford-fulkerson/index_en.html
|
||||
*)
|
49
src/graph.ml
Normal file
49
src/graph.ml
Normal file
|
@ -0,0 +1,49 @@
|
|||
type id = int
|
||||
|
||||
type 'a out_arcs = (id * 'a) list
|
||||
|
||||
(* A graph is just a list of pairs: a node & its outgoing arcs. *)
|
||||
type 'a graph = (id * 'a out_arcs) list
|
||||
|
||||
exception Graph_error of string
|
||||
|
||||
let empty_graph = []
|
||||
|
||||
let node_exists gr id = List.mem_assoc id gr
|
||||
|
||||
let out_arcs gr id =
|
||||
try List.assoc id gr
|
||||
with Not_found -> raise (Graph_error ("Node " ^ string_of_int id ^ " does not exist in this graph."))
|
||||
|
||||
let find_arc gr id1 id2 =
|
||||
let out = out_arcs gr id1 in
|
||||
try Some (List.assoc id2 out)
|
||||
with Not_found -> None
|
||||
|
||||
let new_node gr id =
|
||||
if node_exists gr id then raise (Graph_error ("Node " ^ string_of_int id ^ " already exists in the graph."))
|
||||
else (id, []) :: gr
|
||||
|
||||
let new_arc gr id1 id2 lbl =
|
||||
|
||||
(* Existing out-arcs *)
|
||||
let outa = out_arcs gr id1 in
|
||||
|
||||
(* Update out-arcs.
|
||||
* remove_assoc does not fail if id2 is not bound. *)
|
||||
let outb = (id2, lbl) :: List.remove_assoc id2 outa in
|
||||
|
||||
(* Replace out-arcs in the graph. *)
|
||||
let gr2 = List.remove_assoc id1 gr in
|
||||
(id1, outb) :: gr2
|
||||
|
||||
let n_iter gr f = List.iter (fun (id, _) -> f id) gr
|
||||
|
||||
let n_iter_sorted gr f = n_iter (List.sort compare gr) f
|
||||
|
||||
let n_fold gr f acu = List.fold_left (fun acu (id, _) -> f acu id) acu gr
|
||||
|
||||
let e_iter gr f = List.iter (fun (id1, out) -> List.iter (fun (id2, x) -> f id1 id2 x) out) gr
|
||||
|
||||
let e_fold gr f acu = List.fold_left (fun acu (id1, out) -> List.fold_left (fun acu (id2, x) -> f acu id1 id2 x) acu out) acu gr
|
||||
|
63
src/graph.mli
Normal file
63
src/graph.mli
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
(* Type of a directed graph in which arcs have labels of type 'a. *)
|
||||
type 'a graph
|
||||
|
||||
(* Each node has a unique identifier (a number). *)
|
||||
type id = int
|
||||
|
||||
exception Graph_error of string
|
||||
|
||||
|
||||
(************** CONSTRUCTORS **************)
|
||||
|
||||
(* The empty graph. *)
|
||||
val empty_graph: 'a graph
|
||||
|
||||
(* Add a new node with the given identifier.
|
||||
* @raise Graph_error if the id already exists. *)
|
||||
val new_node: 'a graph -> id -> 'a graph
|
||||
|
||||
(* new_arc gr id1 id2 lbl : adds an arc from node id1 to node id2 with label lbl
|
||||
* Both nodes must already exist in the graph.
|
||||
* If the arc already exists, its label is replaced by lbl.
|
||||
* @raise Graph_error if node id1 or id2 does not exist in the graph. *)
|
||||
val new_arc: 'a graph -> id -> id -> 'a -> 'a graph
|
||||
|
||||
|
||||
(************** GETTERS *****************)
|
||||
|
||||
(* node_exists gr id indicates if the node with identifier id exists in graph gr. *)
|
||||
val node_exists: 'a graph -> id -> bool
|
||||
|
||||
(* Type of lists of outgoing arcs of a node.
|
||||
* An arc is represented by a pair of the destination identifier and the arc label. *)
|
||||
type 'a out_arcs = (id * 'a) list
|
||||
|
||||
(* Find the out_arcs of a node.
|
||||
* @raise Graph_error if the id is unknown in the graph. *)
|
||||
val out_arcs: 'a graph -> id -> 'a out_arcs
|
||||
|
||||
(* find_arc gr id1 id2 finds an arc between id1 and id2 and returns its label. Returns None if the arc does not exist.
|
||||
* @raise Graph_error if id1 is unknown. *)
|
||||
val find_arc: 'a graph -> id -> id -> 'a option
|
||||
|
||||
|
||||
(************** COMBINATORS, ITERATORS **************)
|
||||
|
||||
(* Iterate on all nodes, in no special order. *)
|
||||
val n_iter: 'a graph -> (id -> unit) -> unit
|
||||
|
||||
(* Like n_iter, but the nodes are sorted. *)
|
||||
val n_iter_sorted: 'a graph -> (id -> unit) -> unit
|
||||
|
||||
(* Fold on all (unsorted) nodes. You must remember what List.fold_left does. *)
|
||||
val n_fold: 'a graph -> ('b -> id -> 'b) -> 'b -> 'b
|
||||
|
||||
|
||||
(* Iter on all arcs (edges) *)
|
||||
val e_iter: 'a graph -> (id -> id -> 'a -> unit) -> unit
|
||||
|
||||
(* Fold on all arcs (edges) *)
|
||||
val e_fold: 'a graph -> ('b -> id -> id -> 'a -> 'b) -> 'b -> 'b
|
||||
|
||||
|
Loading…
Reference in a new issue