Newer
Older

Gwennan Eliezer
committed
let () = Random.self_init ();
type action = string

Gwennan Eliezer
committed

Gwennan Eliezer
committed
type grid_arg = {
mutable width: int;
mutable height: int;
}

Gwennan Eliezer
committed
mutable width: float;
mutable height: float;
mutable radius: float;

Gwennan Eliezer
committed
}
type er_prob = float (*between 0 and 1*)
type ba_m = int (*positive*)
type t = {
mutable outputFile: string;
mutable dotUDG: string;
mutable dotUDGrad: string;

Gwennan Eliezer
committed
mutable action: action;
mutable n : int;
mutable grid : grid_arg;
mutable er : er_prob;
mutable ba : ba_m;

Gwennan Eliezer
committed
mutable silent : bool;

Gwennan Eliezer
committed
mutable _args : (string * Arg.spec * string) list;

Gwennan Eliezer
committed
mutable _man : (string * (string list * action) list) list;

Gwennan Eliezer
committed
mutable _others : string list;
mutable _margin : int;
}
let usage_msg do_print_command tool =
"gg is an experimental graph generator.\n"^
(if do_print_command then
("usage: " ^ tool ^ " <graph-kind> [<option>]*\n")

Gwennan Eliezer
committed
else

Gwennan Eliezer
committed
let print_usage output do_print_command tool =
Printf.fprintf output "%s%s" (usage_msg do_print_command tool) (
if (do_print_command) then
"use -h to see the available <graph-kind>.\n\n"
else "use -h to see available <option>.\n"

Gwennan Eliezer
committed

Gwennan Eliezer
committed
{
outputFile = "";
dotUDG = "";
dotUDGrad = "";
action = "void";
n = -1;
grid = {
width = 0;
height = 0;
};
er = 0.3;
ba = 2;
qudg = {
width = 10.;
height = 10.;
radius = 3.;
r1 = 2.;
p = 0.5;
};
silent = false;
directed = false;
_args = [];
_man = [];
_others = [];

Gwennan Eliezer
committed
let first_line b = (
try (
let f = String.index b '\n' in
String.sub b 0 f
) with Not_found -> b
)
let unexpected s = (
prerr_string ("unexpected argument \""^s^"\"");
prerr_newline ();
exit 2 (* unexpected argument *)

Gwennan Eliezer
committed
)
let printSpec args outChannel action (c, messageList) = (
List.iter (fun (ml,action_type) ->

Gwennan Eliezer
committed
if (action = action_type) then

Gwennan Eliezer
committed
let (m1, oth) = match ml with
| h::t -> (h,t)
| _ -> ("",[])
in
let t2 = String.make args._margin ' ' in
let cl = 1 + String.length c in
let t1 = if (cl < args._margin ) then
String.make (args._margin - cl) ' '
else
"\n"^t2
in
Printf.fprintf outChannel " %s%s%s" c t1 m1;

Gwennan Eliezer
committed
List.iter (function x -> Printf.fprintf outChannel "\n%s%s" t2 x) oth ;
Printf.fprintf outChannel "\n" ;

Gwennan Eliezer
committed
) messageList

Gwennan Eliezer
committed
)
let help args tool = (
Printf.printf "%s" (usage_msg (args.action = "void") tool);
(

Gwennan Eliezer
committed
if (args.action = "void") then (
Printf.printf "where <graph-kind> can be:\n";

Gwennan Eliezer
committed
List.iter (printSpec args stdout "") [
("clique",[(["Generate a clique graph"],"")]);
("star",[(["Generate a star graph"],"")]);
("ring",[(["Generate a ring graph"],"")]);
("grid",[(["Generate a grid graph"],"")]);
("HC",[(["Generate a hyper-cube graph"],"")]);

Gwennan Eliezer
committed
("ER",[(["Generate a graph using the Erdos Renyi algo"],"")]);
("BA",[(["Generate a graph using the Barabasi–Albert algo"],"")]);

Gwennan Eliezer
committed
("tree",[(["Generate an acyclic graph (tree)"],"")]);

Gwennan Eliezer
committed
("UDG",[(["Generate a graph using the Unit Disc Graph algo"],"")]);
("QUDG",[(["Generate a graph using the Quasi UDG algo"],"")]);

Gwennan Eliezer
committed
];
Printf.printf "\n";

Gwennan Eliezer
committed
);
Printf.printf "<option> can be:\n";

Gwennan Eliezer
committed
List.iter (printSpec args stdout "void") (List.rev args._man);
if (args.action <> "void") then (

Gwennan Eliezer
committed
Printf.printf "\n";
Printf.printf "<option> specific to this <graph-kind>:\n";

Gwennan Eliezer
committed
List.iter (printSpec args stdout args.action) (List.rev args._man)
) else (
Printf.printf "Use '%s <graph-kind> -h' to see specific options." tool;
Printf.printf "\n";
)

Gwennan Eliezer
committed
);
Printf.printf "\n";
exit 0

Gwennan Eliezer
committed
)
let (mkopt : t -> string list -> ?arg:string -> Arg.spec ->
(string list * action) list -> unit) =
fun opt ol ?(arg="") se ml ->
let add_option o = opt._args <- (o, se, "")::opt._args in
List.iter add_option ol ;
let col1 = (String.concat ", " ol)^arg in

Gwennan Eliezer
committed
opt._man <- (col1, ml)::opt._man

Gwennan Eliezer
committed
(*** User Options Tab **)

Gwennan Eliezer
committed
fun argv args -> (
mkopt args ["--output";"-o"] ~arg:" <string>"

Gwennan Eliezer
committed
(Arg.String (fun s -> args.outputFile <- s))
[(["Redirect stdout into a file"],"void")];

Gwennan Eliezer
committed
let msg = "Set the node number in the graph" in

Gwennan Eliezer
committed
mkopt args ["--nodes-number";"-n"] ~arg:" <int>"

Gwennan Eliezer
committed
(Arg.Int (fun n -> match args.action with
| "grid" | "HC" | "void" -> unexpected "-n"
| _ -> args.n <- n ))

Gwennan Eliezer
committed
[([msg],"clique");([msg],"star");([msg],"ring");
([msg],"ER");([msg],"BA");([msg],"tree");([msg],"UDG");([msg],"QUDG")];

Gwennan Eliezer
committed
mkopt args ["--dimension";"-d"] ~arg:" <int>"
(Arg.Int (fun n -> match args.action with
| "HC"-> args.n <- n
| _ -> unexpected "-d"))
[(["Set the hyper-cube dimension"],"HC")];

Gwennan Eliezer
committed
mkopt args ["--width";"-w"] ~arg:" <float>"
(Arg.Float (fun w -> match args.action with
| "grid" -> args.grid.width <- (int_of_float w)

Gwennan Eliezer
committed
| _ -> unexpected "-w" ))
[(["Set the grid's width \n"],"grid");
(["Set the UDG's terrain width";"10 by default.\n"],"UDG");
(["Set the QUDG's terrain width";"10 by default.\n"],"QUDG")];

Gwennan Eliezer
committed

Gwennan Eliezer
committed
(Arg.Float (fun h -> match args.action with
| "grid" -> args.grid.height <- (int_of_float h)

Gwennan Eliezer
committed
| _ -> unexpected "-he"))
[(["Set the grid's height\n"],"grid");
(["Set the UDG's terrain height";"10 by default.\n"],"UDG");
(["Set the QUDG's terrain height";"10 by default.\n"],"QUDG")];

Gwennan Eliezer
committed

Gwennan Eliezer
committed
mkopt args ["--edge-probability";"-p"]~arg:" <float>"

Gwennan Eliezer
committed
(Arg.Float (fun p -> match args.action with
| "ER" -> args.er <- p
| _ -> unexpected "-p"))
[(["Set the edge appearing probability.";

Gwennan Eliezer
committed
"Must be between 0 and 1, and is set to 0.3 by default\n"],"ER")];

Gwennan Eliezer
committed
mkopt args ["--";"-m"]~arg:" <int>"
(Arg.Int (fun m -> match args.action with
| "BA" -> args.ba <- m
| _ -> unexpected "-m"))
[(["Set the number of edge generated per additional node";

Gwennan Eliezer
committed
"(2 by default)\n"],"BA")];

Gwennan Eliezer
committed

Gwennan Eliezer
committed
mkopt args ["--radius";"-r"]~arg:" <float>"

Gwennan Eliezer
committed
(Arg.Float (fun r -> match args.action with

Gwennan Eliezer
committed
| _ -> unexpected "-r"))
[(["Set the Unit Disc's radius around all nodes.";
mkopt args ["--first-radius";"-r0"]~arg:" <float>"
(Arg.Float (fun r -> match args.action with
| "QUDG" -> args.qudg.radius <- r
| _ -> unexpected "-r0"))
[(["Set the first radius around all nodes.";
mkopt args ["--second-radius";"-r1"]~arg:" <float>"
(Arg.Float (fun r -> match args.action with
| "QUDG" -> args.qudg.r1 <- r
| _ -> unexpected "-r1"))
[(["Set the second radius around all nodes.";
mkopt args ["--probability"]~arg:" <float>"
[(["Sets the probability of the nodes being neighbors when they are ";
"inside the second";
"radius, but not the first one.\n"
], "QUDG")];
let msg = ["Create a DOT file to visualize the UDG plan.";
"When it transformed into a PDF that takes the positioning tags into account";
"(like 'neato' command from GraphViz), each node is visible at the coordinates";
"where they were placed during execution.\n"] in
mkopt args ["--dot-udg";"-du"]~arg:" <file>"
mkopt args ["--dot-udg-radius";"-dur"]~arg:" <file>"

Gwennan Eliezer
committed
[(["Create a DOT file to visualize the UDG plan.";
"Same as the option '-du', but with the radius being also displayed.\n"],"UDG");
(["Create a DOT file to visualize the UDG plan.";
"Same as the option '-du', but with the two radiuses being ";
"also displayed.\n"],"QUDG")];

Gwennan Eliezer
committed
mkopt args ["--silent";"-s"]

Gwennan Eliezer
committed
(Arg.Unit (fun () -> args.silent <- true))

Gwennan Eliezer
committed
mkopt args ["--directed";"-dir"]
(Arg.Unit (fun () -> args.directed <- true))
[(["Generate a directed graph."],"void")];

Gwennan Eliezer
committed

Gwennan Eliezer
committed
mkopt args ["--help";"-h"]

Gwennan Eliezer
committed
(Arg.Unit (fun () -> help args ((argv.(0))^(if args.action = "void" then ""
else " "^args.action))))
[(["Print this help\n"],"void")];

Gwennan Eliezer
committed
)
(* all unrecognized options are accumulated *)
let (add_other : t -> string -> unit) =

Gwennan Eliezer
committed
opt._others <- s::opt._others
let current = ref 1;;
let parse argv = (
let save_current = !current in
let args = make_args () in
mkoptab argv args;
try (
(if (Array.length argv) = 1 then (
print_usage stdout true argv.(0);
exit 1 (* no command or invalid command *)));
let possible_actions =
["clique";"star";"ring";"grid";"HC";"ER";"BA";"tree";"UDG";"QUDG"]
in
(
if (List.mem argv.(1) possible_actions) then args.action <- argv.(1)
else
if (List.mem argv.(1) ["-h";"--help";"-help"]) then help args (argv.(0)) else
(Printf.fprintf stderr "*** Error when calling '%s %s': No such command\n\n"
(argv.(0)) (argv.(1));
(print_usage stderr true argv.(0));
exit 1 (* no command or invalid command *))
);
Arg.parse_argv ~current:current argv args._args (add_other args)
(usage_msg false (argv.(0)^argv.(1)));
current := save_current;
args._others <- List.rev args._others;
args

Gwennan Eliezer
committed
)