Skip to content
Snippets Groups Projects
Commit a0ab40d3 authored by erwan's avatar erwan
Browse files

New: Compute the graph degree, diameter, etc. (closes #3)

merge origin/3-compute-the-graph-degree-diameter-etc
parents ee296a00 a7b23332
No related branches found
No related tags found
1 merge request!4WIP: Resolve "Compute the graph degree, diameter, etc."
Pipeline #26622 passed
(* Time-stamp: <modified the 03/07/2019 (at 10:17) by Erwan Jahier> *)
(* Time-stamp: <modified the 04/07/2019 (at 10:36) by Erwan Jahier> *)
open Sasacore
......@@ -31,6 +31,7 @@ type 's to_register = {
copy_state: 's -> 's;
}
type node_id = string (* cf topology.mli *)
let (to_reg_neigbor : 's Register.neighbor -> 's neighbor) =
fun n ->
......@@ -76,5 +77,13 @@ let (register : 's to_register -> unit) =
let card = Register.card
let get_graph_attribute = Register.get_graph_attribute
let get_graph_attribute = Register.get_graph_attribute
let min_degree = Register.min_degree
let mean_degree = Register.mean_degree
let max_degree = Register.max_degree
let is_cyclic = Register.is_cyclic
let is_connected = Register.is_connected
let is_tree = Register.is_tree
let height = Register.height
let links_number = Register.links_number
let diameter = Register.diameter
(* Time-stamp: <modified the 03/07/2019 (at 10:17) by Erwan Jahier> *)
(* Time-stamp: <modified the 04/07/2019 (at 10:36) by Erwan Jahier> *)
(** Process programmer API *)
type 's neighbor = {
......@@ -41,13 +41,23 @@ type 's to_register = {
If one prepend a value with "some_id=", some_id will we used in
the simulation outputs. Otherwise, an id will be invented *)
type node_id = string (* cf topology.mli *)
(** To be called once *)
val register : 's to_register -> unit
val get_graph_attribute : string -> string
(** Topological infos *)
val card : unit -> int
(* val degree : unit -> int *)
(* val diameter : unit -> int *)
val min_degree : unit -> int
val mean_degree : unit -> float
val max_degree : unit -> int
val is_cyclic : unit -> bool
val is_connected : unit -> bool
val is_tree : unit -> bool
val height : unit -> (node_id -> int) option
val links_number : unit -> int
val diameter : unit -> int
val get_graph_attribute : string -> string
(* take a string and the list of all node and returns the position of the node in the list *)
let (pos:string -> Topology.node list -> int) =
fun nid lid ->
fst (List.fold_left (fun (found_i,i) lid -> if (nid=lid.Topology.id) then (i,i+1) else (found_i,i+1) ) (-1, 0) lid)
(* take a graph t and returns the Adjacency matrix of t *)
let (graph_to_adjency: Topology.t -> int array array) =
fun t->
let taille = List.length t.nodes in
let mat = Array.make_matrix (taille) (taille) 0 in
List.iter (fun n -> (List.iter (fun (_,m) -> mat.(pos n.Topology.id t.nodes).(pos m t.nodes) <- 1 )
(t.succ n.Topology.id) ) ) (t.nodes);
mat
(* Initialize the Adjacency matrix for Floyd Warshall algorithm *)
let (initFW: int array array -> int array array) =
fun m ->
let n = (Array.length m.(0)) in
for i=0 to (n - 1) do
for j=0 to (n - 1) do
if (i<>j) then
(if (m.(i).(j)=1) then m.(i).(j) <- 1 else m.(i).(j) <- n+1)
else m.(i).(j) <- 0
done;
done;
m
(* Apply Floyd Warshall algorithm which gives the matrix of all pairs shortest path *)
let (floydwarshall:int array array -> int array array) =
fun m ->
let w = initFW m in
let n = (Array.length m.(0)) in
for k=0 to (n - 1) do
for i=0 to (n - 1) do
for j=0 to (n - 1) do
w.(i).(j) <- (min (w.(i).(j)) (w.(i).(k) + w.(k).(j)))
done;
done;
done;
w
(* returns the greatest int of a matrix *)
let (max_mat: int array array -> int) =
fun mat ->
let n = (Array.length mat) and m = (Array.length mat.(0)) in
let maxi = ref (-1) in
for i=0 to (n - 1) do
for j=0 to (m - 1) do
maxi := max !maxi mat.(i).(j)
done;
done;
!maxi
(* takes a graph t in argument and returns the diameter *)
let (get: Topology.t -> int ) =
fun t ->
(max_mat(floydwarshall (graph_to_adjency t)))
\ No newline at end of file
val get : Topology.t -> int
(* Time-stamp: <modified the 03/07/2019 (at 10:17) by Erwan Jahier> *)
(* Time-stamp: <modified the 04/07/2019 (at 10:35) by Erwan Jahier> *)
type 's neighbor = {
state: 's ;
......@@ -22,9 +22,29 @@ type 's internal_tables = {
value_of_string : (string, Obj.t) Hashtbl.t;
copy_value : (string, Obj.t) Hashtbl.t;
graph_attributes : (string, string) Hashtbl.t;
mutable card : int
mutable card : int ;
mutable min_deg : int;
mutable mean_deg : float;
mutable max_deg : int;
mutable is_cyclic : bool option;
mutable is_connected : bool option;
mutable is_tree : bool option;
mutable height : (string -> int);
mutable links_number : int;
mutable diameter : int;
}
type properties_functions = {
mutable card : unit -> int;
mutable min_max : unit -> int*int;
mutable mean_deg : unit -> float;
mutable is_connected_cyclic : unit -> bool*bool;
mutable links_number : unit -> int;
mutable diameter : unit -> int
}
type node_id = string (* cf topology.mli *)
let (tbls:'s internal_tables) = {
init_state = Hashtbl.create 1;
enable = Hashtbl.create 1;
......@@ -34,7 +54,25 @@ let (tbls:'s internal_tables) = {
value_of_string = Hashtbl.create 1;
copy_value = Hashtbl.create 1;
graph_attributes = Hashtbl.create 1;
card = (-1)
card = (-1);
min_deg = (-1);
mean_deg = (-1.);
max_deg = (-1);
is_cyclic = None;
is_connected = None;
is_tree = None;
height = (fun _ -> -1);
links_number = (-1);
diameter = (-1)
}
let (prop_funs:properties_functions) = {
card = (fun () -> -1);
min_max = (fun () -> (-1,-1));
mean_deg = (fun () -> -1.);
is_connected_cyclic = (fun () -> (false,false));
links_number = (fun () -> -1);
diameter = (fun () -> -1)
}
let verbose_level = ref 0
......@@ -127,12 +165,103 @@ let (get_copy_value : unit -> ('s -> 's)) = fun () ->
raise (Unregistred ("copy_value", "_global"))
let set_min_max : (unit -> unit) =
fun () ->
let (x,y) = prop_funs.min_max () in
tbls.min_deg <- x;
tbls.max_deg <- y
let set_connec_cycl : (unit -> unit) =
fun () ->
let (x,y) = prop_funs.is_connected_cyclic () in
tbls.is_connected <- Some x;
tbls.is_cyclic <- Some y
let (card : unit -> int) =
fun () -> tbls.card
let (set_card : int -> unit) =
fun i ->
tbls.card <- i
fun () -> match tbls.card with
| -1 -> (let c = prop_funs.card () in tbls.card <- c; c)
| c -> c
let (min_degree : unit -> int) =
fun () -> match tbls.min_deg with
| -1 -> (set_min_max (); tbls.min_deg)
| m -> m
let (mean_degree : unit -> float) =
fun () -> match tbls.mean_deg with
| -1. -> (let m = prop_funs.mean_deg () in tbls.mean_deg <- m; m)
| m -> m
let (max_degree : unit -> int) =
fun () -> match tbls.max_deg with
| -1 -> (set_min_max (); tbls.max_deg)
| m -> m
let (is_cyclic : unit -> bool) =
fun () -> match tbls.is_cyclic with
| None -> (set_connec_cycl ();
match tbls.is_cyclic with
| Some b -> b
| _ -> assert false)
| Some b -> b
let (is_connected : unit -> bool) =
fun () -> match tbls.is_connected with
| None -> (set_connec_cycl ();
match tbls.is_connected with
| Some b -> b
| _ -> assert false)
| Some b -> b
let (is_tree : unit -> bool) =
fun () -> match tbls.is_tree with
| None -> (let b = (not (is_cyclic ()) && (is_connected ())) in tbls.is_tree <- Some b; b)
| Some b -> b
(* Caution : this option is not the same as the option in the type tbls.height.
* If height () = None, then the graph doesn't have a height (because it isn't a tree)*)
let height : (unit -> (string -> int) option) =
fun () ->
if is_tree () then
Some tbls.height
else None
let (links_number : unit -> int) =
fun () -> match tbls.links_number with
| -1 -> (let n = prop_funs.links_number () in tbls.links_number <- n; n)
| n -> n
let (diameter : unit -> int) =
fun () ->
match tbls.diameter with
| -1 -> (let d = (prop_funs.diameter ()) in tbls.diameter <- d; d)
| d -> d
let set_card : ((unit -> int) -> unit) =
fun f -> prop_funs.card <- f
let set_degrees : ((unit -> int*int) -> unit) =
fun f -> prop_funs.min_max <- f
let set_mean_deg : ((unit -> float) -> unit) =
fun f -> prop_funs.mean_deg <- f
let set_is_connected_cyclic : ((unit -> bool*bool) -> unit) =
fun f -> prop_funs.is_connected_cyclic <- f
let set_height : ((node_id -> int) -> unit) =
fun f -> tbls.height <- f
let set_links_number : ((unit -> int) -> unit) =
fun f -> prop_funs.links_number <- f
let set_diameter : ((unit -> int) -> unit) =
fun f -> prop_funs.diameter <- f
let (to_string : 's -> string) =
fun v ->
......
(* Time-stamp: <modified the 03/07/2019 (at 10:18) by Erwan Jahier> *)
(* Time-stamp: <modified the 04/07/2019 (at 10:34) by Erwan Jahier> *)
type 's neighbor = {
state: 's ;
......@@ -13,6 +13,7 @@ type action = string
type 's enable_fun = 's neighbor list -> 's -> action list
type 's step_fun = 's neighbor list -> 's -> action -> 's
type node_id = string (* cf topology.mli *)
val reg_init_state : algo_id -> (int -> 's) -> unit
val reg_enable : algo_id -> 's enable_fun -> unit
......@@ -31,15 +32,31 @@ val get_value_to_string : unit -> 's -> string
val get_value_of_string : unit -> (string -> 's) option
val get_copy_value : unit -> ('s -> 's)
val to_string : 's -> string
val set_card : int -> unit
(* val set_degree : int -> unit *)
(* val set_diameter : int -> unit *)
val card : unit -> int
(* val degree : unit -> int *)
(* val diameter : unit -> int *)
val set_card : (unit -> int) -> unit
val set_degrees : (unit -> int*int) -> unit
val set_mean_deg : (unit -> float) -> unit
val set_is_connected_cyclic : (unit -> bool*bool) -> unit
val set_height : (node_id -> int) -> unit
val set_links_number : (unit -> int) -> unit
val set_diameter : (unit -> int) -> unit
val get_graph_attribute : string -> string
val set_graph_attribute : string -> string -> unit
val card : unit -> int
val min_degree : unit -> int
val mean_degree : unit -> float
val max_degree : unit -> int
val is_cyclic : unit -> bool
val is_connected : unit -> bool
val is_tree : unit -> bool
(** If height () = None, then the graph doesn't have a height (because it isn't a tree)
Otherwise, height () = Some h.*)
val height : unit -> (string -> int) option
val links_number : unit -> int
val diameter : unit -> int
val verbose_level: int ref
......@@ -146,7 +146,66 @@ let (env_rif_decl: SasArg.t -> 'v Process.t list -> string) =
let ssl = get_outputs_rif_decl args pl in
String.concat " "
(List.map (fun (base, tstr) -> Printf.sprintf "\"%s\":%s" base tstr) ssl)
let (get_degree:Topology.t -> int*int) =
fun t -> if t.nodes = [] then 0,0
else
let node_deg n = List.length (t.succ (n.Topology.id)) in
let d_start = node_deg ((List.hd t.nodes)) in
List.fold_left (fun (d_min,d_max) n -> (min (node_deg n) d_min, max (node_deg n) d_max)
) (d_start,d_start) (List.tl t.nodes)
(* take a graph t and a boolean is_oriented and return the number of link in the graph *)
let (get_nb_link: Topology.t -> bool -> int) =
fun t is_oriented ->
if not is_oriented then (List.fold_left (fun acc n -> ((List.length (t.succ n.Topology.id))) + acc) (0) (t.nodes)) / 2
else (List.fold_left (fun acc n -> ((List.length (t.succ n.Topology.id))) + acc) (0) (t.nodes))
let (get_mean_degree : Topology.t -> float) =
fun t ->
(float_of_int (get_nb_link t true)) /. (float_of_int (List.length t.nodes))
let bfs : (Topology.t -> string -> bool * string list) =
fun t n ->
let q = Queue.create () in
let discovered = ref [n] and parent = ref (function _ -> "") in
let cyclic = ref false in
Queue.add n q;
while not (Queue.is_empty q) do
let node = Queue.take q in
parent := List.fold_left (fun parents (_,suc) ->
if List.for_all (fun disc -> disc <> suc) !discovered
then (
Queue.add suc q;
discovered := (suc)::!discovered;
function a -> if a = suc then node else parents a
) else ((
if suc <> (parents node)
then
cyclic := true);
parents
)
) !parent (t.succ node)
done;
(!cyclic, !discovered)
let is_connected_and_cyclic : Topology.t -> bool*bool =
fun t -> match t.nodes with
| [] -> (false,false)
| hd::_ -> let (cyclic,bfs_nodes) = (bfs t hd.Topology.id) in ((List.compare_lengths t.nodes bfs_nodes) = 0, cyclic)
let rec height : string list -> Topology.t -> string -> int =
fun parents t n ->
(List.fold_left (fun h (_,succ) ->
if List.mem succ parents then h else max h (height (n::parents) t succ)) (-1) (t.succ n)) + 1
let get_height : Topology.t -> string -> int =
fun t ->
height ([]) t
let (make : bool -> string array -> 'v t) =
fun dynlink argv ->
let args =
......@@ -167,7 +226,14 @@ let (make : bool -> string array -> 'v t) =
let nl = g.nodes in
let nidl = List.map (fun n -> n.Topology.id) nl in
let nstr = String.concat "," nidl in
Register.set_card (List.length nl);
Register.set_card (fun () -> List.length nl);
Register.set_degrees (fun () -> get_degree g);
Register.set_mean_deg (fun () -> get_mean_degree g);
Register.set_is_connected_cyclic (fun () -> is_connected_and_cyclic g);
Register.set_height (get_height g);
Register.set_links_number (fun () -> get_nb_link g false);
Register.set_diameter (fun () -> Diameter.get g);
Register.verbose_level := args.verbose;
Random.init args.seed;
if !Register.verbose_level > 0 then Printf.eprintf "nodes: %s\nedges:\n" nstr;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment