open Graph open Printf open Ffalgo type path = string (* Format of text files: % This is a comment % define a factory with its id and production rate factory 0 6 % define a village with its id and demand village 1 10 % define a neutral node with its id node 2 % define a road between 2 nodes using their ids and specifying the max capacity road 0 1 2 *) (* Source and destination node We use negative ids to prevent conflicts *) let source = (-1) let destination = (-2) (* Reads a factory node, adds it to the graph and creates an arc from the source *) 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" (* Reads a village node, adds it to the graph and creates an arc to the destination *) 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 neutral node and adds it to the graph *) 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 road and creates and arc between the nodes of the given id and capacity *) 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}