▸Setup and compilation
- To begin with, create a directory for this project.
- In order to save time, a few modules have already been written.
Download these files (save link target as...): graph.mli, graph.ml, gfile.mli, gfile.ml, ftest.ml.
We will explain these files soon. - Since you like downloading stuff, you may also save these files: graph1, graph1.svg.
- The main file is ftest.ml so, we try to compile it, as taught in lesson 6:
ocamlc -o ftest ftest.ml
(try it)-o ftest
indicates the name of the executable.
Error: Unbound module Gfile - Look at the beginning of ftest.ml: we open a module
Gfile
.
Lesson learnt:The modules used by the program must be compiled before the program.
ocamlc -c graph.ml gfile.ml
-c
means compile only, no executable is built.
Error: Could not find the .cmi file for interface graph.mli- A file named graph.mli exists. It is the interface of module
Graph
Lesson learnt:foo.mli must be compiled before foo.ml.
ocamlc -c graph.mli graph.ml gfile.mli gfile.ml
something works, at last.- See which files have been produced:
ls -l
(or more professionally, ls -alhv)
Compilation of C files
file.c compiled into file.o (by gcc) Compilation of OCaml files
file.ml compiled into file.cmo (by ocamlc) file.mli compiled into file.cmi (by ocamlc) ocamlc -o ftest ftest.ml
Error: Required module `Gfile' is unavailable- This error does not come from the compiler but from the linker.
Lesson learnt:When linking (building an executable), the modules must be explicitly given.
ocamlc -o ftest graph.cmo gfile.cmo ftest.ml
Note:When linking, the modules must be explicitly given in the order of dependencies.
- You have obtained an executable ftest.
./ftest
(You get a usage message.)- Whenever you modify a file, you will have to recompile it as well as all the files that depend on it.
▸A few more things about compilation
- Recompiling everything is boring. This is why tools such as GNU make (for almost everything) or ant (for Java) exist. Actually, the java compiler already takes care of dependencies.
- A couple of build tools exist for OCaml too. Let us give a try to ocamlbuild.
- First, remove all the compilation files:
rm -f *.cmi *.cmo ftest
(In order to avoid confusion between tools, ocamlbuild refuses to work if it finds compiled files.) - Use
ocamlbuild ftest.byte
to build the bytecode executable, orocamlbuild ftest.native
to build the native executable. (You need only one of them).
In case you ask, the compiled files can be found in a directory named _build. ./ftest.byte
or./ftest.native
(still prints a usage message, though).
▸Discover the project modules
- You cannot compile the project using ocaml-top. Use any text editor instead, e.g.
emacs
(configured as explained at the beginning of OCaml - Lesson 6) or visual studio code, if you know how to launch it.
You may enjoy A. Bit-Monnot's setup configuration for VSCode : ocaml-maxflow-project on github. - The base project contains two modules and a main program:
- graph.mli and graph.ml which define a module
Graph
- gfile.mli and gfile.ml which define a module
Gfile
- ftest.ml, the main program.
- graph.mli and graph.ml which define a module
- Look at the interfaces of
Graph
(graph.mli) andGfile
All functions are already implemented in graph.ml and gfile.ml
You must not modify the moduleGraph
, but you will have to create new modules and to modify Gfile. - Try to understand the graph file format (look at the example graph1 and read quickly gfile.ml)
- To ease the writing of algorithms, write a new module
Tools
, with the following signature (the signature must be in file tools.mli) :
Interface file
open Graph val clone_nodes: 'a graph -> 'b graph val gmap: 'a graph -> ('a -> 'b) -> 'b graph val add_arc: int graph -> id -> id -> int -> int graph
Implementation file
(* Yes, we have to repeat open Graph. *) open Graph (* assert false is of type ∀α.α, so the type-checker is happy. *) let clone_nodes gr = assert false let gmap gr f = assert false ...
clone_nodes gr
returns a new graph having the same nodes than gr, but no arc. (code : one line)
In order to find your errors more quickly, you may add an annotation :let clone_nodes (gr:'a graph) = ...
gmap gr f
maps all arcs of gr by function f. (⩽3 lines)add_arc g id1 id2 n
adds n to the value of the arc between id1 and id2. If the arc does not exist, it is created.
- In order to test, you may use an online graph editor , and download your graphs.
- In order to visualize graphs, we will use the famous Graphviz library.
Write a new functionexport
inGfile
which writes a string graph in dot format (the format understood by graphviz). To understand the expected format, you just have to look at this example (click on the picture to get the source file).
To generate an image from a dot file, you can use:dot -Tsvg your-dot-file > some-output-file.svg
▸To be done
- Minimal acceptable project: you should at least implement the Ford-Fulkerson algorithm (in a separate module) and test it on several examples.
- You all remember the 3 MIC lecture on Graphs by Marie-Jo Huguet.
- An interactive presentation of the algorithm.
- A french presentation of flow problems (see "Algorithmes des graphes / Flots").
- Medium project: find a use-case of this algorithm (e.g. network transportation, bandwidth, or bipartite matching) and write a program that solves the problem, given input files easier to write than graph files.
- An example with money sharing.
- Wikipedia offers several examples on its max flow page.
- The cricket elimination problem
- Finding where guests will sleep.
- Bipartite matching
- Object recognition through bipartite matching
- Better project: enhance the medium project by taking into account other constraints - and implementing the max-flow min-cost algorithm.
As an example, your program could be used to match a set of people to a set of ressources (e.g. students to projets tutorés, or future students to universites as in late APB) taking into account people's preferences. Your system should be as fair as possible and avoid biases.
▸Some technical support
Debugging
In order to activate debugging:- You must create a file named _tags in your project directory (this file is read by ocamlbuild).
Add the following line:true: debug
- In the terminal, set the variable OCAMLRUNPARAM to b (means: backtrace)
export OCAMLRUNPARAM="b"
then, you can launch your program.
Packages
- If you use special modules, such as Unix (package name: unix) or Graphics (package name: graphics), you need to tell ocamlbuild to use the corresponding
package. In the file _tags, add the following line:
true: package(unix)
ortrue: package(unix,graphics,...)
- In order to build, you have to use:
ocamlbuild -use-ocamlfind myprog.native
ocamlfind (findlib) is a tool written by a prolific OCaml developper: Gerd Stolpmann. It is a library manager for OCaml.
How to start writing the Ford-Fulkerson algorithm (alert: SPOILER)
If you are stuck, you may start by writing a function which finds a path in a graph:
(* A path is a list of nodes. *)
type path = id list
(* find_path gr forbidden id1 id2
* returns None if no path can be found.
* returns Some p if a path p from id1 to id2 has been found.
*
* forbidden is a list of forbidden nodes (they have already been visited)
*)
find_path: int graph -> id list -> id -> id -> path option