243 lines
19 KiB
HTML
243 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
<!-- Page generated by OCaml with Ocsigen.
|
||
See http://ocsigen.org/ and http://caml.inria.fr/ for information -->
|
||
<html class="ocaml" lang="en" id="h" xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
<title>OCaml - mini project</title>
|
||
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||
<link media="all" href="../ystyle.css" rel="stylesheet" />
|
||
<script src="../Scripts/yfold.js"></script>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="header" id="header">
|
||
<h1 id="title">OCaml - mini project</h1>
|
||
<nav><a class="caml_c" title="Back to main page" href="../ocaml.html" data-eliom-c-onclick="bOmVzvczyxF3"></a></nav>
|
||
</div>
|
||
<main>
|
||
<section class="yfold">
|
||
<h3 class="yfold-title" onclick="toggleYfold('8a36b6ec')"><span class="arrow" id="arrow-8a36b6ec">▸</span>Setup and compilation</h3>
|
||
<div class="yfold-content" id="content-8a36b6ec" data-yfold-default="hide">
|
||
<ul class="steps">
|
||
<li>To begin with, create a directory for this project.</li>
|
||
<li>In order to save time, a few modules have already been written. <br />Download these files <small class="pcom">(save link target as...)</small>: <span class="file"><a class="caml_c" href="project-files/graph.mli"
|
||
data-eliom-c-onclick="0uSqfBGDN549">graph.mli</a></span>, <span class="file"><a class="caml_c" href="project-files/graph.ml" data-eliom-c-onclick="AkPsJ43v5R2W">graph.ml</a></span>, <span class="file"><a class="caml_c"
|
||
href="project-files/gfile.mli" data-eliom-c-onclick="BcpQIw927mux">gfile.mli</a></span>, <span class="file"><a class="caml_c" href="project-files/gfile.ml" data-eliom-c-onclick="irnXIzp0LvLL">gfile.ml</a></span>, <span class="file"><a
|
||
class="caml_c" href="project-files/ftest.ml" data-eliom-c-onclick="PBCKLM+8oRx9">ftest.ml</a></span>. <br />We will explain these files soon.</li>
|
||
<li>Since you like downloading stuff, you may also save these files: <span class="file"><a class="caml_c" href="project-files/graph1" data-eliom-c-onclick="o8X2TiD3cChj">graph1</a></span>, <span class="file"><a class="caml_c"
|
||
href="project-files/graph1.svg" data-eliom-c-onclick="uca+xD0CCdCZ">graph1.svg</a></span>. </li>
|
||
<li>The main file is <span class="hfile">ftest.ml</span> so, we try to compile it, as taught in lesson 6: <br /><code class="command">ocamlc -o ftest ftest.ml</code><small class="pcom">(try it) </small><code class="inline">-o ftest</code>
|
||
indicates the name of the executable.<br /><samp class="errmsg">Error: Unbound module Gfile</samp></li>
|
||
<li>Look at the beginning of <span class="file">ftest.ml</span>: we open a module <code class="inline">Gfile</code>. <br />Lesson learnt: <q>The modules used by the program must be compiled <b>before</b> the program.</q></li>
|
||
<li><code class="command">ocamlc -c graph.ml gfile.ml</code><code class="inline">-c</code> means compile only, no executable is built.<br /><samp class="errmsg">Error: Could not find the .cmi file for interface graph.mli</samp></li>
|
||
<li>A file named <span class="file">graph.mli</span> exists. It is the <b>interface</b> of module <code class="block"><span class="uident">Graph</span>
|
||
</code><br />Lesson learnt: <q>foo.mli must be compiled <b>before</b> foo.ml.</q></li>
|
||
<li><code class="command">ocamlc -c graph.mli graph.ml gfile.mli gfile.ml</code><br /><small class="pcom">something works, at last.</small></li>
|
||
<li>See which files have been produced: <code class="command">ls -l</code><small class="pcom"> (or more professionally, ls -alhv)</small><br />
|
||
<div class="examples">
|
||
<div class="example">
|
||
<h5>Compilation of C files</h5>
|
||
<table>
|
||
<tr>
|
||
<td class="col1"><span class="hfile">file.c</span></td>
|
||
<td class="col2"> compiled into </td>
|
||
<td class="col3"><span class="hfile">file.o</span></td>
|
||
<td class="col4"><small class="pcom"> (by gcc)</small></td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<div class="example">
|
||
<h5>Compilation of OCaml files</h5>
|
||
<table>
|
||
<tr>
|
||
<td class="col1"><span class="hfile">file.ml</span></td>
|
||
<td class="col2"> compiled into </td>
|
||
<td class="col3"><span class="hfile">file.cmo</span></td>
|
||
<td class="col4"><small class="pcom"> (by ocamlc)</small></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="col1"><span class="hfile">file.mli</span></td>
|
||
<td class="col2"> compiled into </td>
|
||
<td class="col3"><span class="hfile">file.cmi</span></td>
|
||
<td class="col4"><small class="pcom"> (by ocamlc)</small></td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
<li><code class="command">ocamlc -o ftest ftest.ml</code><br /><samp class="errmsg">Error: Required module `Gfile' is unavailable</samp></li>
|
||
<li>This error does not come from the <i>compiler</i> but from the <i>linker</i>. <br />Lesson learnt: <q>When linking (building an executable), the modules must be explicitly given.</q></li>
|
||
<li><code class="command">ocamlc -o ftest graph.cmo gfile.cmo ftest.ml</code><br />Note: <q>When linking, the modules must be explicitly given <b> in the order of dependencies.</b></q></li>
|
||
<li>You have obtained an executable <span class="file">ftest</span>. </li>
|
||
<li><code class="command">./ftest</code><small class="pcom"> (You get a usage message.)</small></li>
|
||
<li>Whenever you modify a file, you will have to recompile it as well as <b>all</b> the files that depend on it.</li>
|
||
</ul>
|
||
</div>
|
||
<script>
|
||
//<![CDATA[
|
||
initYfold('8a36b6ec');
|
||
//]]>
|
||
</script>
|
||
</section>
|
||
<section class="yfold">
|
||
<h3 class="yfold-title" onclick="toggleYfold('9588387f')"><span class="arrow" id="arrow-9588387f">▸</span>A few more things about compilation</h3>
|
||
<div class="yfold-content" id="content-9588387f" data-yfold-default="hide">
|
||
<ul class="steps">
|
||
<li>Recompiling everything is boring. This is why tools such as <a target="_blank" href="https://www.gnu.org/software/make/manual/html_node/index.html">GNU make</a><small class="pcom"> (for almost everything)</small> or <a target="_blank"
|
||
href="https://www.tutorialspoint.com/ant/index.htm">ant</a><small class="pcom"> (for Java) </small> exist. <small class="pcom">Actually, the java compiler already takes care of dependencies.</small></li>
|
||
<li>A couple of build tools exist for OCaml too. Let us give a try to <b>ocamlbuild</b>. </li>
|
||
<li>First, remove all the compilation files: <code class="command">rm -f *.cmi *.cmo ftest</code><small class="pcom">(In order to avoid confusion between tools, ocamlbuild refuses to work if it finds compiled files.)</small></li>
|
||
<li>Use <code class="command">ocamlbuild ftest.byte</code> to build the bytecode executable, or <code class="command">ocamlbuild ftest.native</code> to build the native executable. (You need only one of them).<br /><small class="pcom">In
|
||
case you ask, the compiled files can be found in a directory named <span class="file">_build</span>. </small></li>
|
||
<li><code class="command">./ftest.byte</code> or <code class="command">./ftest.native</code><small class="pcom">(still prints a usage message, though).</small></li>
|
||
</ul>
|
||
</div>
|
||
<script>
|
||
//<![CDATA[
|
||
initYfold('9588387f');
|
||
//]]>
|
||
</script>
|
||
</section>
|
||
<section class="yfold">
|
||
<h3 class="yfold-title" onclick="toggleYfold('14504082')"><span class="arrow" id="arrow-14504082">▸</span>Discover the project modules</h3>
|
||
<div class="yfold-content" id="content-14504082" data-yfold-default="hide">
|
||
<ul class="steps">
|
||
<li>You cannot compile the project using ocaml-top. Use any text editor instead, e.g. <code class="command">emacs</code><small class="pcom"> (configured as explained at the beginning of <a class="caml_c" href="sujet6.html"
|
||
data-eliom-c-onclick="X4YxKfFrPGLk">OCaml - Lesson 6</a>) </small> or visual studio code, if you know how to launch it.<br />You may enjoy A. Bit-Monnot's setup <b>configuration for VSCode</b> : <a target="_blank"
|
||
href="https://github.com/arthur-bit-monnot/ocaml-maxflow-project">ocaml-maxflow-project on github</a>. </li>
|
||
<li>The base project contains two modules and a main program:<ul>
|
||
<li><span class="file">graph.mli</span> and <span class="file">graph.ml</span> which define a module <code class="block"><span class="uident">Graph</span>
|
||
</code></li>
|
||
<li><span class="file">gfile.mli</span> and <span class="file">gfile.ml</span> which define a module <code class="block"><span class="uident">Gfile</span>
|
||
</code></li>
|
||
<li><span class="file">ftest.ml</span>, the main program.</li>
|
||
</ul>
|
||
</li>
|
||
<li>Look at the interfaces of <code class="block"><span class="uident">Graph</span>
|
||
</code>(<span class="file">graph.mli</span>) and <code class="block"><span class="uident">Gfile</span>
|
||
</code><br />All functions are already implemented in <span class="file">graph.ml</span> and <span class="file">gfile.ml</span><br /><b>You must not modify the module <code class="block"><span class="uident">Graph</span>
|
||
</code></b>, but you will have to create new modules and to modify Gfile. </li>
|
||
<li>Try to understand the graph file format (look at the example <span class="file">graph1</span> and read quickly gfile.ml)</li>
|
||
<li>To ease the writing of algorithms, write a new module <code class="block"><span class="uident">Tools</span>
|
||
</code>, with the following signature <small class="pcom">(the signature must be in file tools.mli)</small> :<br />
|
||
<div class="examples">
|
||
<div class="example">
|
||
<h5>Interface file</h5><code class="block"><span class="kw">open</span> <span class="uident">Graph</span>
|
||
|
||
<span class="kw">val</span> clone_nodes: 'a graph -> 'b graph
|
||
<span class="kw">val</span> gmap: 'a graph -> ('a -> 'b) -> 'b graph
|
||
<span class="kw">val</span> add_arc: int graph -> id -> id -> int -> int graph
|
||
</code>
|
||
</div>
|
||
<div class="example">
|
||
<h5>Implementation file</h5><code class="block"><span class="comment">(* Yes, we have to repeat open Graph. *)</span>
|
||
<span class="kw">open</span> <span class="uident">Graph</span>
|
||
|
||
<span class="comment">(* assert false is of type ∀α.α, so the type-checker is happy. *)</span>
|
||
<span class="kw">let</span> <span class="letvar">clone_nodes</span> gr = <span class="kw">assert</span> <span class="kw">false</span>
|
||
<span class="kw">let</span> <span class="letvar">gmap</span> gr f = <span class="kw">assert</span> <span class="kw">false</span>
|
||
...
|
||
</code>
|
||
</div>
|
||
</div>
|
||
<ul>
|
||
<li><code class="block">clone_nodes gr
|
||
</code> returns a new graph having the same nodes than gr, but no arc.<small class="pcom"> (code : one line)</small><br />In order to find your errors more quickly, you may add an annotation : <code class="block"><span
|
||
class="kw">let</span> <span class="letvar">clone_nodes</span> (gr:'a graph) = ...
|
||
</code></li>
|
||
<li><code class="block">gmap gr f
|
||
</code> maps all arcs of gr by function f.<small class="pcom"> (⩽3 lines)</small></li>
|
||
<li><code class="block">add_arc g id1 id2 n
|
||
</code> adds n to the value of the arc between id1 and id2. If the arc does not exist, it is created.</li>
|
||
</ul>
|
||
</li>
|
||
<li>In order to test, you may use an <a target="_blank" href="https://www-m9.ma.tum.de/graph-algorithms/flow-ford-fulkerson/index_en.html">online graph editor</a><span class="menu"> (Create a graph)</span>, and download your graphs.</li>
|
||
<li>In order to visualize graphs, we will use the famous <a target="_blank" href="http://www.graphviz.org/">Graphviz library</a>. <br />Write a new function <code class="block">export
|
||
</code> in <code class="block"><span class="uident">Gfile</span>
|
||
</code> which writes a string graph in dot format (the format understood by graphviz). To understand the expected format, you just have to look at <a target="_blank" href="https://graphviz.gitlab.io/_pages/Gallery/directed/fsm.html">this
|
||
example</a><small class="pcom"> (click on the picture to get the source file)</small>. <br />To generate an image from a dot file, you can use: <br /><code class="command">dot -Tsvg your-dot-file > some-output-file.svg</code></li>
|
||
</ul>
|
||
</div>
|
||
<script>
|
||
//<![CDATA[
|
||
initYfold('14504082');
|
||
//]]>
|
||
</script>
|
||
</section>
|
||
<section class="yfold">
|
||
<h3 class="yfold-title" onclick="toggleYfold('41d55fee')"><span class="arrow" id="arrow-41d55fee">▸</span>To be done</h3>
|
||
<div class="yfold-content" id="content-41d55fee" data-yfold-default="hide">
|
||
<ul class="steps">
|
||
<li><b>Minimal acceptable project: </b>you should at least implement the Ford-Fulkerson algorithm (in a separate module) and test it on several examples. <ul>
|
||
<li>You all remember the <a target="_blank" href="https://homepages.laas.fr/huguet/drupal/content/enseignement-3mic"> 3 MIC lecture on Graphs</a> by Marie-Jo Huguet.</li>
|
||
<li><a target="_blank" href="https://www-m9.ma.tum.de/graph-algorithms/flow-ford-fulkerson/index_en.html">An interactive presentation of the algorithm</a>. </li>
|
||
<li>A<a target="_blank" href="https://www-npa.lip6.fr/blin/enseignements/"> french presentation of flow problems</a> (see "Algorithmes des graphes / Flots"). </li>
|
||
</ul>
|
||
</li>
|
||
<li><b>Medium project: </b>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. <ul>
|
||
<li><a target="_blank" href="https://hackernoon.com/max-flow-algorithm-in-real-life-551ebd781b25">An example with money sharing.</a></li>
|
||
<li>Wikipedia offers several examples on its <a target="_blank" href="https://en.wikipedia.org/wiki/Maximum_flow_problem">max flow page</a>. </li>
|
||
<li><a target="_blank" href="https://medium.com/swlh/real-world-network-flow-cricket-elimination-problem-55a3036a5d60">The cricket elimination problem</a></li>
|
||
<li><a target="_blank" href="https://www.anishathalye.com/2015/09/24/algorithms-in-the-real-world-host-matching/">Finding where guests will sleep.</a></li>
|
||
<li><a target="_blank" href="https://www.geeksforgeeks.org/maximum-bipartite-matching/">Bipartite matching</a></li>
|
||
<li><a target="_blank" href="http://www.cs.toronto.edu/~sven/Papers/bipartite.pdf">Object recognition through bipartite matching</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><b>Better project: </b>enhance the medium project by taking into account other constraints - and implementing the max-flow min-cost algorithm.<br />As an example, your program could be used to match a set of people to a set of
|
||
ressources (e.g. students to <i>projets tutorés</i>, 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.</li>
|
||
</ul>
|
||
</div>
|
||
<script>
|
||
//<![CDATA[
|
||
initYfold('41d55fee');
|
||
//]]>
|
||
</script>
|
||
</section>
|
||
<section class="yfold">
|
||
<h3 class="yfold-title" onclick="toggleYfold('ee09a9ff')"><span class="arrow" id="arrow-ee09a9ff">▸</span>Some technical support</h3>
|
||
<div class="yfold-content" id="content-ee09a9ff" data-yfold-default="hide">
|
||
<h4>Debugging</h4>In order to activate debugging: <ul class="steps">
|
||
<li>You must create a file named <span class="hfile">_tags</span> in your project directory (this file is read by ocamlbuild).<br />Add the following line:
|
||
<pre>true: debug</pre>
|
||
</li>
|
||
<li>In the terminal, set the variable <var>OCAMLRUNPARAM</var> to <var>b</var><small class="pcom"> (means: backtrace)</small><br /><code class="command">export OCAMLRUNPARAM="b"</code>then, you can launch your program.</li>
|
||
</ul>
|
||
<h4>Packages</h4>
|
||
<ul>
|
||
<li>If you use special modules, such as <var>Unix</var><small class="pcom"> (package name: unix)</small> or <var>Graphics</var><small class="pcom"> (package name: graphics)</small>, you need to tell ocamlbuild to use the corresponding
|
||
package. In the file <span class="hfile">_tags</span>, add the following line:
|
||
<pre>true: package(unix)</pre> or
|
||
<pre>true: package(unix,graphics,...)</pre>
|
||
</li>
|
||
<li>In order to build, you have to use:<code class="command">ocamlbuild -use-ocamlfind myprog.native</code><br class="bbr" /><b>ocamlfind</b> (findlib) is a tool written by a prolific OCaml developper: <a target="_blank"
|
||
href="http://www.gerd-stolpmann.de/buero/freie_sw_beitraege.html.en">Gerd Stolpmann</a>. It is a library manager for OCaml.</li>
|
||
</ul>
|
||
<h4>How to start writing the Ford-Fulkerson algorithm (alert: SPOILER)</h4>
|
||
<p>If you are stuck, you may start by writing a function which finds a path in a graph:</p><code class="block">
|
||
<span class="comment">(* A path is a list of nodes. *)</span>
|
||
<span class="kw">type</span> path = id list
|
||
|
||
<span class="comment">(* 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)
|
||
*)</span>
|
||
find_path: int graph -> id list -> id -> id -> path option
|
||
|
||
</code>
|
||
</div>
|
||
<script>
|
||
//<![CDATA[
|
||
initYfold('ee09a9ff');
|
||
//]]>
|
||
</script>
|
||
</section>
|
||
</main>
|
||
<footer><small class="pcom"><a class="caml_c" href="../yversion.html" data-eliom-c-onclick="QkmB87Beytxc">Version information</a></small><a target="_blank" href="http://www.insa-toulouse.fr"><img title="INSA Toulouse"
|
||
style="width:73px;height:28px;" alt="INSA logo" src="../Images/logo-insa-light.jpg" /></a><a target="_blank" href="http://jigsaw.w3.org/css-validator/check/referer"><img title="Validate css stylesheet" style="width:28px;height:32px;"
|
||
alt="CSS3 logo" src="../Images/css3.png" /></a><a target="_blank" href="http://validator.w3.org/check/referer"><img title="Validate html5 content" style="width:32px;height:32px;" alt="HTML5 logo" src="../Images/html5.png" /></a></footer>
|
||
</body>
|
||
|
||
</html>
|