Changeset 1990 in genesis for nodes/channelga.ml
- Timestamp:
- Apr 12, 2004, 12:01:27 AM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
nodes/channelga.ml
r1980 r1990 1 (* a few constants *) 2 let population_size = 20 1 (** 2 Experimental channel assigning program using an evolutionary algorithm. 3 4 The scoring function is simple: 5 - the score of a combination of two interfaces is 1 if there's two or more 6 channels between them, -1 if there's 1 channel between them, -5 if 7 there's no channels between them (they're on adjacent channels) and -10 8 if they're on the same channel 9 - the score for a node is the sum of the scores of all the combinations of 10 interfaces for that node, minus any node-specific penalties (eg. 11 channels 7, 8 and 9 are unusable and score -1000 on node x), scaled by 12 the number of interfaces to give more weight to larger nodes (the 13 assumption being that larger nodes are more important nodes) 14 - the total score of the network is the sum of the score of the nodes, 15 minus any network-wide penalties (eg. the omni's for node x and node y 16 can see eachother, so they should be apart) 17 18 - install an O'Caml compiler. /usr/ports/lang/ocaml/ in FreeBSD, ocaml in 19 Debian. 20 21 - compile with 22 23 $ ocamlopt -o foo str.cmxa channelga.ml 24 25 - run with 26 27 $ ./foo f 28 29 where f is the result of running prepconf.py on a file with a list of 30 paths to the wleiden.conf's to consider. 31 *) 32 33 (* a few constants suitable for twiddling *) 34 (** How large a population should the system maintain? *) 35 let population_size = 100 36 (** How long should the system iterate after an improvement? *) 3 37 and max_stagnant_iterations = 10000 4 and mutation_rate = 0.05;; 38 (** What is the chance for an ESSID to channel assignment to mutate to a 39 random channel? *) 40 and mutation_rate = 0.1;; 5 41 6 42 (* the type definitions. note that Caml has trouble with mutually recursive … … 20 56 node_wis: wi list; 21 57 };; 22 23 let nodes = Hashtbl.create 4;; 24 let groups = Hashtbl.create 4;; 58 (** A configuration is an assignment of groups, identified by essid, to a 59 channel, plus a score. The code should be careful not to use the score 60 between mutating an re-evaluating. *) 61 type configuration = { 62 mutable score: int; 63 conf: (string, int) Hashtbl.t; 64 };; 65 type 'a maybe = Nothing | Just of 'a;; 66 67 (** The global nodes hash, mapping from node name to node struct. *) 68 let nodes = Hashtbl.create 4 69 (** The global groups hash, mapping from essid to group struct. *) 70 let groups = Hashtbl.create 4 25 71 26 72 (* some convenience functions *) 27 let compose f g = fun x -> f(g(x));; 28 let ($) = compose;; 29 let maketuple a b = (a, b);; 30 let head = List.hd;; 31 let tail = List.tl;; 32 (* given a hashtable, return all the keys as a list *) 33 let keys t = Hashtbl.fold (fun k d a -> k::a) t [];; 34 (* given a hashtable, return all the values as a list *) 35 let values t = Hashtbl.fold (fun k d a -> d::a) t [];; 36 let 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 73 74 (** Function composition. *) 75 let compose f g = fun x -> f(g(x)) 76 let ($) = compose 77 (** Turn two individual values into a tuple *) 78 let maketuple a b = (a, b) 79 (** Shorthand for List.hd *) 80 let head = List.hd 81 (** Shorthand for List.tail *) 82 let tail = List.tl 83 let just x = match x with 84 Nothing -> assert false 85 | Just s -> s 86 (** Given a hashtable, return all the keys as a list *) 87 let keys t = Hashtbl.fold (fun k d a -> k::a) t [] 88 (** Given a hashtable, return all the values as a list *) 89 let values t = Hashtbl.fold (fun k d a -> d::a) t [] 90 (** Copy one array into the other *) 91 let copyarray src dest = Array.blit src 0 dest 0 (Array.length src) 92 93 (** Given a list, return a list of pairs with all possible combinations of 39 94 items from the given list *) 40 95 let rec combinations l = 41 96 match l with 42 97 [] -> [] 43 | x::xs -> (List.map (maketuple x) xs)@(combinations xs) ;;44 45 (* given a configuration and two wi's, return the score *)98 | x::xs -> (List.map (maketuple x) xs)@(combinations xs) 99 100 (** Given a configuration and two wi's, return the score *) 46 101 let wi_score c wi1 wi2 = 47 102 let scoretable = [ ((<=) 2, 1); … … 58 113 runtable scoretable;; 59 114 60 (* given a configuration and a node, return the score. this is simply the sum of115 (** Given a configuration and a node, return the score. this is simply the sum of 61 116 the scores of all the combinations of interfaces, written down as a fold for 62 117 efficiency *) … … 64 119 let foldfunc acc (wi1, wi2) = acc + (wi_score c wi1 wi2) in 65 120 let base_score = List.fold_left foldfunc 0 (combinations n.node_wis) in 66 base_score * (List.length n.node_wis);; 67 68 let score_configuration c (ns: node list) = 121 base_score * (List.length n.node_wis) 122 123 (** Given a list of nodes and a configuration, return the score for the whole 124 configuration. This is the sum of the scores for all nodes. *) 125 let score_configuration ns c = 69 126 let foldfunc acc n = acc + (node_score (Hashtbl.find c) n) in 70 127 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 given128 nodescores 129 130 (** Given a filename, return a list of all the lines in the file with the given 74 131 filename *) 75 132 let snarf_lines fname = … … 83 140 with End_of_file -> !result 84 141 85 let parse_pair nodename (wname, gname) = 86 let new_wi = { wi_name = wname; wi_nodename = nodename; wi_essid = gname} in 142 (** Given the name of the node currently being parsed, parse the given tuple 143 that consists of a wi name and an essid. *) 144 let parse_pair nodename (wname, essid) = 145 let new_wi = { wi_name = wname; wi_nodename = nodename; wi_essid = essid} in 87 146 let foo = try 88 let group = Hashtbl.find groups gnamein147 let group = Hashtbl.find groups essid in 89 148 group.group_wis <- new_wi::group.group_wis; 90 149 with Not_found -> 91 let group = { group_essid = gname; group_wis = [ new_wi ] } in92 Hashtbl.add groups gnamegroup in150 let group = { group_essid = essid; group_wis = [ new_wi ] } in 151 Hashtbl.add groups essid group in 93 152 new_wi 94 153 … … 112 171 the global 'groups' hash instead of getting it passed in from above, that 113 172 hash is empty. *) 114 let 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 *) 120 let 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);; 173 let random_configuration groups evaluate = 174 let h = Hashtbl.create 30 in 175 Hashtbl.iter (fun k _ -> Hashtbl.add h k (1 + (Random.int 12))) groups; 176 { score = (evaluate h); conf = h } 127 177 128 178 let print_conf conf = … … 149 199 List.iter (do_fields $ (Str.split spacere)) (snarf_lines fname);; 150 200 151 let 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 201 (** Generalized evolutionary algorithm driver. 202 initialize: () -> configuration array 203 recombine: 204 mutate: configuration array -> configuration array 205 evaluate: configuration array -> configuration array 206 select: configuration array -> configuration array 207 208 and the result is the best configuration *) 209 let evolutionary_algorithm initialize recombine mutate evaluate select = 210 let population = (evaluate $ initialize) () in 211 let last_high_score = ref population.(0).score in 157 212 let iterations_since_new_high_score = ref 0 in 158 213 let generation = ref 0 in 159 214 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 215 let _ = while !iterations_since_new_high_score < max_stagnant_iterations do 216 let newpop = (recombine $ mutate $ evaluate $ select) population in 217 Array.sort (fun a b -> compare b.score a.score) newpop; 218 copyarray newpop population; 219 let high_score = population.(0).score in 177 220 if high_score > !last_high_score then begin 178 221 last_high_score := high_score; … … 188 231 incr iterations_since_new_high_score; 189 232 incr generation 190 done; 191 print_conf population.(0);; 233 done in 234 population.(0);; 235 236 let main = 237 parse_file Sys.argv.(1); 238 parse_nodeclusters "coupled.conf"; 239 Random.self_init(); 240 let all_nodes = values nodes in 241 let evaluate_hash = score_configuration all_nodes in 242 let initialize () = Array.init population_size (fun _ -> random_configuration groups evaluate_hash) in 243 let recombine x = x in 244 let mutate_conf conf = 245 Hashtbl.iter (fun essid _ -> let f = Random.float 1.0 in 246 let group = Hashtbl.find groups essid in 247 let maxchannel = if (List.length group.group_wis) == 1 then 11 248 else 13 in 249 if (f < mutation_rate) then 250 Hashtbl.replace conf essid (1 + (Random.int maxchannel))) conf in 251 let mutate population = let mutants = Array.map (fun c -> let hash = Hashtbl.copy c.conf in 252 mutate_conf hash; 253 { score = evaluate_hash hash; 254 conf = hash}) population in 255 Array.append population mutants in 256 let evaluate population = Array.iter (fun c -> c.score <- evaluate_hash c.conf) population; 257 population in 258 let select p = Array.sub p 0 ((Array.length p) / 2) in 259 let best = evolutionary_algorithm initialize recombine mutate evaluate select in 260 print_conf best.conf;; 192 261 193 262 main
Note:
See TracChangeset
for help on using the changeset viewer.