css-le-botlan/Y/OCaml/project.html
2021-02-13 08:54:03 +01:00

243 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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">&#x25b8;</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">&#x25b8;</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">&#x25b8;</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 -&gt; 'b graph
<span class="kw">val</span> gmap: 'a graph -&gt; ('a -&gt; 'b) -&gt; 'b graph
<span class="kw">val</span> add_arc: int graph -&gt; id -&gt; id -&gt; int -&gt; 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 &gt; 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">&#x25b8;</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 &quot;Algorithmes des graphes / Flots&quot;). </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">&#x25b8;</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=&quot;b&quot;</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 -&gt; id list -&gt; id -&gt; id -&gt; 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>