add circulation problem resolution

This commit is contained in:
Arnaud Vergnet 2020-11-24 15:20:02 +01:00
parent 656d48a3ed
commit 236600e387
8 changed files with 215 additions and 129 deletions

5
.gitignore vendored
View file

@ -1,4 +1,7 @@
_build/ _build/
ftest.native ftest.native
circulationtest.native
outfile outfile
*~ *~
test/
run/

View file

@ -20,33 +20,44 @@ edit:
demo: build demo: build
@echo $(EXECUTING) @echo $(EXECUTING)
./ftest.native graphs/graph1 1 2 outfile ./ftest.native graphs/graph1 1 2 test/outfile
@echo $(RESULT) @echo $(RESULT)
@cat outfile @cat test/outfile
test: build test: build
@echo $(EXECUTING) @echo $(EXECUTING)
./ftest.native graphs/graph1 1 2 outfile ./ftest.native graphs/graph1 1 2 test/outfile
@echo $(BUILDING_SVG) @echo $(BUILDING_SVG)
@echo "outfile..." @echo "outfile..."
@dot -Tsvg outfile > outfile.svg @dot -Tsvg test/outfile > test/outfile.svg
@echo "graph_init..." @echo "graph_init..."
@dot -Tsvg graph_init > graph_init.svg @dot -Tsvg test/graph_init > test/graph_init.svg
@echo "graph_apply..." @echo "graph_apply..."
@dot -Tsvg graph_apply > graph_apply.svg @dot -Tsvg test/graph_apply > test/graph_apply.svg
@echo "graph_res..." @echo "graph_res..."
@dot -Tsvg graph_res > graph_res.svg @dot -Tsvg test/graph_res > test/graph_res.svg
@echo "" @echo ""
run: build run: build
@echo $(EXECUTING) @echo $(EXECUTING)
./ftest.native graphs/test1 0 3 solution ./ftest.native graphs/test2 0 5 run/solution
@echo $(BUILDING_SVG) @echo $(BUILDING_SVG)
@echo "solution..." @echo "solution..."
@dot -Tsvg solution > solution.svg @dot -Tsvg run/solution > run/solution.svg
@echo "" @echo ""
clean: clean:
-rm -rf _build/ -rm -rf _build/
-rm ftest.native -rm ftest.native
build_circulation:
@echo $(COMPILING)
ocamlbuild circulationtest.native
run_circulation: build_circulation
@echo $(EXECUTING)
./circulationtest.native circulation_input_graphs/test1 run/circulation_solution
@echo $(BUILDING_SVG)
@echo "solution..."
@dot -Tsvg run/circulation_solution > run/circulation_solution.svg

View file

@ -0,0 +1,27 @@
% Factories
% factory id production_rate
factory 0 6
factory 1 6
% Villages
% village id demand
village 5 10
village 6 10
village 7 10
% n id
node 2
node 3
node 4
road 0 1 2
road 0 2 4
road 0 3 4
road 1 2 3
road 1 4 3
road 2 3 5
road 4 3 3
road 4 5 1
road 4 6 5
road 2 6 4
road 2 7 1

15
graphs/test2 Normal file
View file

@ -0,0 +1,15 @@
% Graph saved at Fri Nov 20 2020 14:11:39 GMT+0100 (Central European Standard Time)
n 130 200
n 225 300
n 325 300
n 175 100
n 275 100
n 370 200
e 0 1 15
e 1 2 12
e 2 5 7
e 0 3 4
e 3 4 10
e 4 5 10
e 2 3 3
e 4 1 5

View file

@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.43.0 (0)
-->
<!-- Title: finite_state_machine Pages: 1 -->
<svg width="388pt" height="155pt"
viewBox="0.00 0.00 388.00 155.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 151)">
<title>finite_state_machine</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-151 384,-151 384,4 -4,4"/>
<!-- 0 -->
<g id="node1" class="node">
<title>0</title>
<ellipse fill="none" stroke="black" cx="18" cy="-72" rx="18" ry="18"/>
<text text-anchor="middle" x="18" y="-68.3" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- 1 -->
<g id="node2" class="node">
<title>1</title>
<ellipse fill="none" stroke="black" cx="190" cy="-129" rx="18" ry="18"/>
<text text-anchor="middle" x="190" y="-125.3" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- 0&#45;&gt;1 -->
<g id="edge3" class="edge">
<title>0&#45;&gt;1</title>
<path fill="none" stroke="black" d="M34.06,-80.87C40.15,-84.27 47.3,-88.04 54,-91 91.02,-107.38 100.76,-111.03 140,-121 147.07,-122.8 154.83,-124.28 162.04,-125.46"/>
<polygon fill="black" stroke="black" points="161.66,-128.94 172.07,-126.97 162.7,-122.02 161.66,-128.94"/>
<text text-anchor="middle" x="104" y="-119.8" font-family="Times,serif" font-size="14.00">7</text>
</g>
<!-- 2 -->
<g id="node3" class="node">
<title>2</title>
<ellipse fill="none" stroke="black" cx="190" cy="-18" rx="18" ry="18"/>
<text text-anchor="middle" x="190" y="-14.3" font-family="Times,serif" font-size="14.00">2</text>
</g>
<!-- 0&#45;&gt;2 -->
<g id="edge1" class="edge">
<title>0&#45;&gt;2</title>
<path fill="none" stroke="black" d="M32.43,-61.03C45.34,-51.14 65.8,-37.1 86,-30 110.59,-21.36 140.3,-18.65 161.49,-17.93"/>
<polygon fill="black" stroke="black" points="161.79,-21.43 171.71,-17.72 161.64,-14.43 161.79,-21.43"/>
<text text-anchor="middle" x="104" y="-33.8" font-family="Times,serif" font-size="14.00">8</text>
</g>
<!-- 3 -->
<g id="node4" class="node">
<title>3</title>
<ellipse fill="none" stroke="black" cx="104" cy="-72" rx="18" ry="18"/>
<text text-anchor="middle" x="104" y="-68.3" font-family="Times,serif" font-size="14.00">3</text>
</g>
<!-- 0&#45;&gt;3 -->
<g id="edge2" class="edge">
<title>0&#45;&gt;3</title>
<path fill="none" stroke="black" d="M36.4,-72C47.74,-72 62.77,-72 75.68,-72"/>
<polygon fill="black" stroke="black" points="75.9,-75.5 85.9,-72 75.9,-68.5 75.9,-75.5"/>
<text text-anchor="middle" x="61" y="-75.8" font-family="Times,serif" font-size="14.00">10</text>
</g>
<!-- 4 -->
<g id="node5" class="node">
<title>4</title>
<ellipse fill="none" stroke="black" cx="276" cy="-77" rx="18" ry="18"/>
<text text-anchor="middle" x="276" y="-73.3" font-family="Times,serif" font-size="14.00">4</text>
</g>
<!-- 1&#45;&gt;4 -->
<g id="edge8" class="edge">
<title>1&#45;&gt;4</title>
<path fill="none" stroke="black" d="M205.55,-119.22C211.8,-115.08 219.21,-110.23 226,-106 234.08,-100.96 243.01,-95.61 251.02,-90.89"/>
<polygon fill="black" stroke="black" points="253.02,-93.78 259.88,-85.7 249.48,-87.73 253.02,-93.78"/>
<text text-anchor="middle" x="233" y="-109.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- 5 -->
<g id="node6" class="node">
<title>5</title>
<ellipse fill="none" stroke="black" cx="362" cy="-108" rx="18" ry="18"/>
<text text-anchor="middle" x="362" y="-104.3" font-family="Times,serif" font-size="14.00">5</text>
</g>
<!-- 1&#45;&gt;5 -->
<g id="edge9" class="edge">
<title>1&#45;&gt;5</title>
<path fill="none" stroke="black" d="M208.07,-127.11C233.69,-124.24 283.64,-118.53 326,-113 328.56,-112.67 331.22,-112.31 333.88,-111.94"/>
<polygon fill="black" stroke="black" points="334.51,-115.39 343.92,-110.52 333.53,-108.45 334.51,-115.39"/>
<text text-anchor="middle" x="276" y="-124.8" font-family="Times,serif" font-size="14.00">21</text>
</g>
<!-- 2&#45;&gt;4 -->
<g id="edge4" class="edge">
<title>2&#45;&gt;4</title>
<path fill="none" stroke="black" d="M207.14,-24.75C217.04,-29.24 229.75,-35.66 240,-43 245.51,-46.95 251,-51.75 255.94,-56.49"/>
<polygon fill="black" stroke="black" points="253.64,-59.14 263.18,-63.75 258.6,-54.2 253.64,-59.14"/>
<text text-anchor="middle" x="233" y="-46.8" font-family="Times,serif" font-size="14.00">12</text>
</g>
<!-- 3&#45;&gt;1 -->
<g id="edge7" class="edge">
<title>3&#45;&gt;1</title>
<path fill="none" stroke="black" d="M119.25,-81.67C132.04,-90.35 151.05,-103.25 165.99,-113.39"/>
<polygon fill="black" stroke="black" points="164.44,-116.56 174.68,-119.28 168.37,-110.77 164.44,-116.56"/>
<text text-anchor="middle" x="147" y="-106.8" font-family="Times,serif" font-size="14.00">11</text>
</g>
<!-- 3&#45;&gt;2 -->
<g id="edge6" class="edge">
<title>3&#45;&gt;2</title>
<path fill="none" stroke="black" d="M117.76,-60.27C124.18,-54.68 132.22,-48.12 140,-43 147.49,-38.07 156.07,-33.4 163.94,-29.46"/>
<polygon fill="black" stroke="black" points="165.59,-32.55 173.06,-25.04 162.54,-26.25 165.59,-32.55"/>
<text text-anchor="middle" x="147" y="-46.8" font-family="Times,serif" font-size="14.00">2</text>
</g>
<!-- 3&#45;&gt;4 -->
<g id="edge5" class="edge">
<title>3&#45;&gt;4</title>
<path fill="none" stroke="black" d="M122.24,-72.51C151.84,-73.38 212.57,-75.16 247.89,-76.2"/>
<polygon fill="black" stroke="black" points="247.87,-79.7 257.97,-76.5 248.08,-72.71 247.87,-79.7"/>
<text text-anchor="middle" x="190" y="-77.8" font-family="Times,serif" font-size="14.00">5</text>
</g>
<!-- 4&#45;&gt;5 -->
<g id="edge10" class="edge">
<title>4&#45;&gt;5</title>
<path fill="none" stroke="black" d="M293.2,-82.98C305.17,-87.39 321.7,-93.5 335.44,-98.57"/>
<polygon fill="black" stroke="black" points="334.26,-101.86 344.85,-102.04 336.68,-95.3 334.26,-101.86"/>
<text text-anchor="middle" x="319" y="-97.8" font-family="Times,serif" font-size="14.00">14</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

100
src/circulationfile.ml Normal file
View file

@ -0,0 +1,100 @@
open Graph
open Printf
open Ffalgo
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 source = (-1)
let destination = (-2)
let read_factory graph line =
try Scanf.sscanf line "factory %d %d" (fun id capacity -> new_arc (new_node graph id) source id capacity)
with e ->
Printf.printf "Cannot read factory in line - %s:\n%s\n%!" (Printexc.to_string e) line ;
failwith "from_file"
let read_village graph line =
try Scanf.sscanf line "village %d %d" (fun id capacity -> new_arc (new_node graph id) id destination capacity)
with e ->
Printf.printf "Cannot read village in line - %s:\n%s\n%!" (Printexc.to_string e) line ;
failwith "from_file"
(* Reads a line with a node. *)
let read_node graph line =
try Scanf.sscanf line "node %d" (fun id -> 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_road graph line =
try Scanf.sscanf line "road %d %d %d"
(fun id1 id2 capacity -> new_arc (ensure (ensure graph id1) id2) id1 id2 capacity)
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 circulation_from_file path =
let infile = open_in path in
(* create source and destination *)
let initial_graph = new_node (new_node empty_graph source) destination in
(* Read all lines until end of file.
* n is the current node counter. *)
let rec loop graph =
try
let line = input_line infile in
(* Remove leading and trailing spaces. *)
let line = String.trim line in
let graph2 =
(* Ignore empty lines *)
if line = "" then graph
(* The first character of a line determines its content : n or e. *)
else match line.[0] with
| 'f' -> read_factory graph line
| 'v' -> read_village graph line
| 'n' -> read_node graph line
| 'r' -> read_road graph line
(* It should be a comment, otherwise we complain. *)
| _ -> read_comment graph line
in
loop graph2
with End_of_file -> graph (* Done *)
in
let final_graph = loop initial_graph in
close_in infile ;
{graph = final_graph; origin = source; destination = destination}

11
src/circulationfile.mli Normal file
View file

@ -0,0 +1,11 @@
(* Read a graph from a file,
* Write a graph to a file. *)
open Graph
open Ffalgo
type path = string
val circulation_from_file: path -> int network

38
src/circulationtest.ml Normal file
View file

@ -0,0 +1,38 @@
open Circulationfile
open Gfile
open Tools
open Ffalgo
let flow_to_string gr = gmap gr (fun fl -> String.concat "/" [(string_of_int fl.current); (string_of_int fl.capacity)])
let () =
(* Check the number of command-line arguments *)
if Array.length Sys.argv <> 3 then
begin
Printf.printf "\nUsage: %s infile outfile\n\n%!" Sys.argv.(0) ;
exit 0
end ;
(* Arguments are : infile(1) source-id(2) sink-id(3) outfile(4) *)
let infile = Sys.argv.(1)
and outfile = Sys.argv.(2)
in
(* Open file *)
let initial_network = circulation_from_file infile in
(* Execute FF *)
let solution_network = run_ff initial_network in
(* Print max flow *)
let () = Printf.printf "Max flow: %d\n%!" (get_max_flow solution_network) in
(* Convert to string for export *)
let final_graph = flow_to_string solution_network.graph in
(* Rewrite the graph that has been read. *)
let () = export outfile final_graph in
()