source: genesis/nodes/channelga.ml@ 1980

Last change on this file since 1980 was 1980, checked in by lodewijk, 21 years ago
  • oops, prepconf.py vergeten te committen. maakt van een lijst van wleiden.conf paden een invoer file voor channelga.ml
  • het supernode concept geport, een virtuele node met een stel echte nodes als kinderen waarvan de interfaces bij elkaar worden genomen (cetim1, 2 & 3 bv)
  • interface file erbij met begin van documentatie
File size: 6.9 KB
Line 
1(* a few constants *)
2let population_size = 20
3and max_stagnant_iterations = 10000
4and mutation_rate = 0.05;;
5
6(* the type definitions. note that Caml has trouble with mutually recursive
7 data structures. you can define them, you just can't ever instantiate them.
8 this is why the fields in wi are all loose references by way of strings *)
9type wi = {
10 wi_name: string;
11 wi_nodename: string;
12 wi_essid: string;
13};;
14type group = {
15 group_essid: string;
16 mutable group_wis: wi list;
17};;
18type node = {
19 node_name: string;
20 node_wis: wi list;
21};;
22
23let nodes = Hashtbl.create 4;;
24let groups = Hashtbl.create 4;;
25
26(* some convenience functions *)
27let compose f g = fun x -> f(g(x));;
28let ($) = compose;;
29let maketuple a b = (a, b);;
30let head = List.hd;;
31let tail = List.tl;;
32(* given a hashtable, return all the keys as a list *)
33let keys t = Hashtbl.fold (fun k d a -> k::a) t [];;
34(* given a hashtable, return all the values as a list *)
35let values t = Hashtbl.fold (fun k d a -> d::a) t [];;
36let copyarray src dest = Array.blit src 0 dest 0 (Array.length src);;
37
38(* given a list, return a list of pairs with all possible combinations of
39 items from the given list *)
40let rec combinations l =
41 match l with
42 [] -> []
43 | x::xs -> (List.map (maketuple x) xs)@(combinations xs);;
44
45(* given a configuration and two wi's, return the score *)
46let wi_score c wi1 wi2 =
47 let scoretable = [ ((<=) 2, 1);
48 ((==) 2, -1);
49 ((==) 1, -5);
50 ((==) 0, -10) ] in
51 let channel1 = c wi1.wi_essid in
52 let channel2 = c wi2.wi_essid in
53 let diff = abs (channel1 - channel2) in
54 let rec runtable t = match t with
55 [] -> assert false
56 | (cond, s)::xs -> if (cond diff) then s
57 else runtable xs in
58 runtable scoretable;;
59
60(* given a configuration and a node, return the score. this is simply the sum of
61 the scores of all the combinations of interfaces, written down as a fold for
62 efficiency *)
63let node_score c n =
64 let foldfunc acc (wi1, wi2) = acc + (wi_score c wi1 wi2) in
65 let base_score = List.fold_left foldfunc 0 (combinations n.node_wis) in
66 base_score * (List.length n.node_wis);;
67
68let score_configuration c (ns: node list) =
69 let foldfunc acc n = acc + (node_score (Hashtbl.find c) n) in
70 let nodescores = List.fold_left foldfunc 0 ns in
71 nodescores;;
72
73(* given a filename, return a list of all the lines in the file with the given
74 filename *)
75let snarf_lines fname =
76 let infile = open_in fname in
77 let result = ref [] in
78 try
79 while true do
80 result := (input_line infile)::!result
81 done;
82 !result (* never gets here *)
83 with End_of_file -> !result
84
85let parse_pair nodename (wname, gname) =
86 let new_wi = { wi_name = wname; wi_nodename = nodename; wi_essid = gname} in
87 let foo = try
88 let group = Hashtbl.find groups gname in
89 group.group_wis <- new_wi::group.group_wis;
90 with Not_found ->
91 let group = { group_essid = gname; group_wis = [ new_wi ] } in
92 Hashtbl.add groups gname group in
93 new_wi
94
95let parse_fields fields =
96 let nodename = head fields in
97 let rec makepairs l = match l with
98 [] -> []
99 | x::[] -> assert false
100 | a::b::xs -> (a, b)::(makepairs xs) in
101 let wis = List.map (parse_pair nodename) (makepairs (tail fields)) in
102 let sorted_wis = List.sort compare wis in
103 let node = { node_name = nodename; node_wis = sorted_wis } in
104 Hashtbl.add nodes nodename node
105
106let parse_file fname =
107 let spacere = Str.regexp " " in
108 List.iter (parse_fields $ (Str.split spacere)) (snarf_lines fname)
109 ;;
110
111(** Return a random configuration. For some reason, if this function accesses
112 the global 'groups' hash instead of getting it passed in from above, that
113 hash is empty. *)
114let random_configuration groups =
115 let conf = Hashtbl.create 30 in
116 Hashtbl.iter (fun k _ -> Hashtbl.add conf k (1 + (Random.int 12))) groups;
117 conf
118
119(* Mutate the configuration in the given population at the given offset *)
120let mutate p i =
121 Hashtbl.iter (fun essid _ -> let f = Random.float 1.0 in
122 let group = Hashtbl.find groups essid in
123 let maxchannel = if (List.length group.group_wis) == 1 then 11
124 else 13 in
125 if (f < mutation_rate) then
126 Hashtbl.replace p.(i) essid (1 + (Random.int maxchannel))) p.(i);;
127
128let print_conf conf =
129 let print_wi wi = wi.wi_name ^ ": " ^ (string_of_int (Hashtbl.find conf wi.wi_essid)) in
130 let wis node = List.fold_left (fun acc wi -> acc ^ " " ^ (print_wi wi)) "" node.node_wis in
131 let sorted_nodes = List.sort (fun a b -> compare (a.node_name) (b.node_name)) (values nodes) in
132 List.iter (fun n -> print_string (n.node_name ^ ":" ^ (wis n) ^ "\n")) sorted_nodes
133
134let parse_nodeclusters fname =
135 let spacere = Str.regexp " " in
136 (* handle a row of fields. the first field is the supernode name, the
137 rest are the subnode names. create a new node for the supernode,
138 stuff all the wi's of the subnodes under it, names prefixed with
139 their original node's names for clarity, and remove the subnodes
140 from the nodes hashtable *)
141 let do_fields f = let nodename = head f in
142 let subnodenames = tail f in
143 let subnodes = List.map (Hashtbl.find nodes) subnodenames in
144 List.iter (Hashtbl.remove nodes) subnodenames;
145 let prefixed_wis n = List.map (fun w -> { w with wi_name = n.node_name ^ "." ^ w.wi_name}) n.node_wis in
146 let wis = List.fold_left (fun a s -> a@(prefixed_wis s)) [] subnodes in
147 let node = { node_name = nodename; node_wis = wis } in
148 Hashtbl.add nodes nodename node in
149 List.iter (do_fields $ (Str.split spacere)) (snarf_lines fname);;
150
151let main =
152 parse_file Sys.argv.(1);
153 parse_nodeclusters "coupled.conf";
154 Random.self_init();
155 let population = Array.init population_size (fun _ -> random_configuration groups) in
156 let last_high_score = ref (-1000000) in
157 let iterations_since_new_high_score = ref 0 in
158 let generation = ref 0 in
159 let all_nodes = values nodes in
160 while !iterations_since_new_high_score < max_stagnant_iterations do
161 (* mutate the population *)
162 for i = 0 to (population_size / 2 - 1) do
163 let i2 = i + population_size / 2 in
164 population.(i2) <- Hashtbl.copy population.(i);
165 mutate population (i2)
166 done;
167 (* sort the populations according to score. to do this, make
168 a list of (score, solution) tuples *)
169 let score_pop = Array.map (fun c -> ((score_configuration c all_nodes), c)) population in
170 (* sort on the first field *)
171 Array.sort (fun x y -> compare (fst y) (fst x)) score_pop;
172 (* extract the, now sorted, configuration and put it into population *)
173 copyarray (Array.map snd score_pop) population;
174 (* now look at the best score and update the highscore if
175 necessary *)
176 let high_score = fst score_pop.(0) in
177 if high_score > !last_high_score then begin
178 last_high_score := high_score;
179 iterations_since_new_high_score := 0
180 end;
181 assert (!last_high_score >= high_score);
182 if (!generation mod 10) == 0 then begin
183 print_int !generation;
184 print_string ": ";
185 print_int !last_high_score;
186 print_newline();
187 end;
188 incr iterations_since_new_high_score;
189 incr generation
190 done;
191 print_conf population.(0);;
192
193main
Note: See TracBrowser for help on using the repository browser.