diff --git a/graphs/graph2 b/graphs/graph2 index d1f9b02..f0dd799 100644 --- a/graphs/graph2 +++ b/graphs/graph2 @@ -1,11 +1,25 @@ -%% +%% Enter the 2 sets one after the other +%% each element separated by a coma s a,b,c,d,e,f s j1,j2,j3,j4,j5,j6 -%% preferences' format : p x -> y : pref n°Z -%% (Z from 1 to size of the second set (|S2|) ) +%% Enter the capacity for the second set /!\ INT only +%% either a single number which will be the capacity of every second set's element +%% or a list of number such as |list| = |S2| +%% ex : +%% s a,b,c,d,e,f,g,h,i,j,k,l +%% s j1,j2,j3 +%% c 5,20,10 +%% (c 5 <=> c 5,5,5 in this case) + +c 1 + +%% Enter the preferences one by one with the format : elemS1 -> elemS2 : pref n°X /!\ INT only for X +%% with X from 1 to |S2|, 1 being the most desired, |S2| being the least desired +%% (You can actually put any number, the rule is that for X and Y, X < Y, +%% the element corresponding to X is more preferred than the one corresponding to Y) p a -> j2 : pref n°1 p a -> j3 : pref n°2 diff --git a/src/BGAlgorithm.ml b/src/BGAlgorithm.ml index 6cdb4e0..bffde4c 100644 --- a/src/BGAlgorithm.ml +++ b/src/BGAlgorithm.ml @@ -93,10 +93,10 @@ let get_final_graph (initGraph : (int * int) graph) (residualGraph : (int * int) let busacker_gowen_algorithm (graph : (int * int) graph) (origin : id) (sink : id) = let flow = 0 in let totalCost = 0 in - + let initGraph = graph in let rec boucle graph origin sink flow totalCost = - + let path = get_path graph origin sink in match path with |None -> (flow, totalCost, graph) diff --git a/src/BPgfile.ml b/src/BPgfile.ml index 482e410..0f69920 100644 --- a/src/BPgfile.ml +++ b/src/BPgfile.ml @@ -6,20 +6,35 @@ open Str type path = string (* Format of text files: - % + %% Enter the 2 sets one after the other + %% each element separated by a coma - % s a,b,c,d,e,f s j1,j2,j3,j4,j5,j6 - % + %% Enter the capacity for the second set /!\ INT only + %% either a single number which will be the capacity of every second set's element + %% or a list of number such as |list| = |S2| + %% ex : + %% s a,b,c,d,e,f,g,h,i,j,k,l + %% s j1,j2,j3 + %% c 5,20,10 + %% (c 5 <=> c 5,5,5 in this case) + + c 1 + + %% Enter the preferences one by one with the format : elemS1 -> elemS2 : pref n°X /!\ INT only for X + %% with X from 1 to |S2|, 1 being the most desired, |S2| being the least desired + %% (You can actually put any number, the rule is that for X and Y, X < Y, + %% the element corresponding to X is more preferred than the one corresponding to Y) + p a -> j2 : pref n°1 - p a -> j3 : pref n°1 + p a -> j3 : pref n°2 p c -> j1 : pref n°1 - p c -> j4 : pref n°1 + p c -> j4 : pref n°2 p d -> j3 : pref n°1 p e -> j3 : pref n°1 - p e -> j4 : pref n°1 + p e -> j4 : pref n°2 p f -> j6 : pref n°1 *) @@ -45,20 +60,27 @@ let read_comment graph line = Printf.printf "Unknown line:\n%s\n%!" line ; failwith "from_file" -(* Reads a line with a user. *) +(* Reads a line with a set of nodes. *) let read_set graph id lId setNumber line = - (* let regexSplit = Str.regexp "(\\[|,|\\])" in *) try Scanf.sscanf line "s %s" (fun set -> set_lNodes graph (String.split_on_char ',' set) id lId setNumber ) with e -> - Printf.printf "Cannot read node in line - %s:\n%s\n%!" (Printexc.to_string e) line ; + Printf.printf "Cannot read node set in line - %s:\n%s\n%!" (Printexc.to_string e) line ; failwith "from_file" -(* Reads a line with a payement. *) +(* Reads a line with a preference. *) let read_preference graph lId line = try Scanf.sscanf line "p %s -> %s : pref n°%s" (fun nodeSet1 nodeSet2 weight -> set_preference graph nodeSet1 nodeSet2 weight lId) with e -> - Printf.printf "Cannot read arc in line - %s:\n%s\n%!" (Printexc.to_string e) line ; + Printf.printf "Cannot read preference in line - %s:\n%s\n%!" (Printexc.to_string e) line ; + failwith "from_file" + +(* Reads a line with the capacity for the second set. *) +let read_capacity line = + try Scanf.sscanf line "c %s" + (fun capacity -> (String.split_on_char ',' capacity)) + with e -> + Printf.printf "Cannot read capacity in line - %s:\n%s\n%!" (Printexc.to_string e) line ; failwith "from_file" @@ -69,34 +91,34 @@ let from_file path = (* Read all lines until end of file. * n is the current node counter. *) - let rec loop n graph lId setNumber= + let rec loop n graph lId setNumber capacitySet2= try let line = input_line infile in (* Remove leading and trailing spaces. *) let line = String.trim line in - let ((n2, graph2, l2) , setNumber2) = + let ((n2, graph2, l2) , setNumber2, capacitySet22) = (* Ignore empty lines *) - if line = "" then ((n, graph, lId), setNumber) + if line = "" then ((n, graph, lId), setNumber, capacitySet2 ) (* The first character of a line determines its content : u or p. *) else match line.[0] with - | 's' -> (read_set graph n lId setNumber line, setNumber+1) - | 'p' -> ((n, read_preference graph lId line, lId), 0) + | 's' -> (read_set graph n lId setNumber line, setNumber+1, capacitySet2) + | 'p' -> ((n, read_preference graph lId line, lId), 0, capacitySet2) + | 'c' -> ((n, graph, lId), 0, read_capacity line) (* It should be a comment, otherwise we complain. *) - | _ -> ((n, read_comment graph line, lId), 1) + | _ -> ((n, read_comment graph line, lId), 1, capacitySet2) in - loop n2 graph2 l2 setNumber2 + loop n2 graph2 l2 setNumber2 capacitySet22 - with End_of_file -> (graph, lId) (* Done *) + with End_of_file -> (graph, lId, capacitySet2) (* Done *) in - let (graph, lId) = loop 1 empty_graph [] 1 in - + let (graph, lId, capacitySet2) = loop 1 empty_graph [] 1 [] in (* Users with negative balance linked to the origin Users with positive balance linked to sink *) - let graph = create_source_sink_and_link graph lId in + let graph = create_source_sink_and_link graph lId capacitySet2 in (* Link users between themselves with *) (*let graph = link_users graph lId in *) close_in infile ; diff --git a/src/bp.ml b/src/bp.ml index 1ede6ca..21bb40c 100644 --- a/src/bp.ml +++ b/src/bp.ml @@ -31,6 +31,7 @@ let set_preference graph (nodeNameSet1 : string) (nodeNameSet2 : string) (weight new_arc graph idS1 idS2 (weight, "1") +(* Link the source to every node with "setNumber"=1 with cost=capacity=1 *) let link_node_to_set graph lId nodeId = List.fold_left ( fun acu (_,id,setNumber) -> @@ -40,21 +41,38 @@ let link_node_to_set graph lId nodeId = ) graph lId -let link_set_to_node graph lId nodeId = - List.fold_left ( - fun acu (_,id,setNumber) -> - if setNumber = 2 - then new_arc acu id nodeId ("1", "1") - else acu - ) graph lId +(* Link the every node with "setNumber"=2 to the sink with cost=1 and capacity=capacitySet2 + Corresponds to the case where every node should have the same capacity*) +let rec link_set_to_node_single graph lId nodeId capacitySet2 = + List.fold_left ( + fun acu (_,id,setNumber) -> + if setNumber = 2 + then new_arc acu id nodeId ("1",List.hd capacitySet2) + else acu + ) graph lId + +(* Link the every node with "setNumber"=2 to the sink with cost=1 and different capacities + Corresponds to the case where every node should have a different capacity*) +let rec link_set_to_node_multiple graph lId nodeId capacitySet2 = match lId with + |[] -> graph + |(_,id,setNumber) :: rest1 -> if setNumber = 2 then + begin + match capacitySet2 with + |[]-> graph + |e :: rest2 -> link_set_to_node_multiple (new_arc graph id nodeId ("1",e)) rest1 nodeId rest2 + end + else link_set_to_node_multiple graph rest1 nodeId capacitySet2 -let create_source_sink_and_link graph lId = +let create_source_sink_and_link graph lId capacitySet2 = let graph = new_node graph 0 in let sinkId = (get_max_id graph)+1 in let graph = new_node graph sinkId in - let graph = link_node_to_set graph lId 0 in - link_set_to_node graph lId sinkId + let graph = link_node_to_set graph lId 0 in + if List.length capacitySet2 = 1 + then link_set_to_node_single graph lId sinkId capacitySet2 + else link_set_to_node_multiple graph lId sinkId capacitySet2 + let remove_source_sink_zeroes graph = let max_id = (get_max_id graph) in diff --git a/src/bp.mli b/src/bp.mli index 1089d36..5180cc0 100644 --- a/src/bp.mli +++ b/src/bp.mli @@ -19,10 +19,10 @@ val set_lNodes : (string * string ) graph -> string list -> id -> (string * id * (* Creates an arc between two nodes with a certain weight (cost) and a capacity of 1 (weigth, 1) in a (string * string) graph *) val set_preference : (string * string ) graph -> string -> string -> string -> (string * id * int) list -> (string * string ) graph -(* Creates a source with id=0 and a sink with id=n+1, n number of nodes in the graph. +(* Creates a source with id=0 and a sink with id=n+1, with n the number of nodes in the graph. Then creates an arc between the source and every node with setNumber=1 - and an arc between the sink and every node with setNumber=2*) -val create_source_sink_and_link : (string * string ) graph -> (string * id * int) list -> (string * string ) graph + and an arc between the sink and every node with setNumber=2 with the specified capacities, either a single number or a set of capacity*) +val create_source_sink_and_link : (string * string ) graph -> (string * id * int) list -> string list -> (string * string ) graph (* Create a new graph without : the source and its arcs, the sink and its arcs, every arc whose flow=0 *) val remove_source_sink_zeroes : (string * string) graph -> (string * string) graph diff --git a/src/ftest_advanced.ml b/src/ftest_advanced.ml index fb51677..04a3837 100644 --- a/src/ftest_advanced.ml +++ b/src/ftest_advanced.ml @@ -2,7 +2,6 @@ open BPgfile open Tool open BGAlgorithm open BLF -open Format open Sys open Printf open Bp @@ -23,15 +22,11 @@ let () = (* Arguments are : infile(1) source-id(2)*) - - let infile = Sys.argv.(1) and outfile = Sys.argv.(2) in - let () = printf "debug args\n" in - (* These command-line arguments are not used for the moment. *) (* Open file *) diff --git a/src/ftest_basic.ml b/src/ftest_basic.ml index 48f160b..38883ef 100644 --- a/src/ftest_basic.ml +++ b/src/ftest_basic.ml @@ -1,11 +1,8 @@ open Gfile open Tool open BGAlgorithm -open BLF -open Format open Sys open Printf -open Bp let () = @@ -14,13 +11,14 @@ let () = ex : ./ftest_basic.native graphs/graph1 graphs/graph3 0 5 *) (* Check the number of command-line arguments *) + + if Array.length Sys.argv <> 5 then begin Printf.printf "\nUsage: %s infile source sink outfile\n\n%!" Sys.argv.(0) ; exit 0 end ; - (* Arguments are : infile(1) outfile(2) source-id(3) sink-id(4) *) @@ -34,8 +32,6 @@ let () = in - let () = printf "debug args\n" in - (* These command-line arguments are not used for the moment. *) (* Open file *) @@ -47,15 +43,12 @@ let () = (* Rewrite the graph that has been read. *) let (flow, cout, finalGraph) = busacker_gowen_algorithm initGraph _source _sink in - (*let finalGraph = remove_ss_zeroes finalGraph in*) let () = printf "max flow = %d, cout = %d\n" flow cout in let () = write_file outfile finalGraph in let () = export outfile finalGraph in - (* let () = export infile graph in *) - (*Uncomment the following line if you have graphviz installed *) - let retour = command ("dot -Tsvg "^outfile^".dot > "^outfile^".svg") in + (*let retour = command ("dot -Tsvg "^outfile^".dot > "^outfile^".svg") in*) () diff --git a/src/gfile.ml b/src/gfile.ml index dff9a13..acf2ee7 100644 --- a/src/gfile.ml +++ b/src/gfile.ml @@ -4,17 +4,19 @@ open Printf type path = string (* Format of text files: - % This is a comment + %% This is a comment - % A node with its coordinates (which are not used). + %% 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. + %% 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 + %% Enter the edges from one node to another one by one + %% format to test basic program : + %% e id1 id2 cost capacity + e 3 1 5 20 + e 0 2 8 10 *)