Changeset 1990 in genesis for nodes/channelga.ml


Ignore:
Timestamp:
Apr 12, 2004, 12:01:27 AM (21 years ago)
Author:
lodewijk
Message:

prutsen met channelga.ml

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? *)
     35let population_size = 100
     36(** How long should the system iterate after an improvement? *)
    337and 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? *)
     40and mutation_rate = 0.1;;
    541
    642(* the type definitions. note that Caml has trouble with mutually recursive
     
    2056        node_wis: wi list;
    2157};;
    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. *)
     61type configuration = {
     62        mutable score: int;
     63        conf: (string, int) Hashtbl.t;
     64};;
     65type 'a maybe = Nothing | Just of 'a;;
     66
     67(** The global nodes hash, mapping from node name to node struct. *)
     68let nodes = Hashtbl.create 4
     69(** The global groups hash, mapping from essid to group struct. *)
     70let groups = Hashtbl.create 4
    2571
    2672(* 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. *)
     75let compose f g = fun x -> f(g(x))
     76let ($) = compose
     77(** Turn two individual values into a tuple *)
     78let maketuple a b = (a, b)
     79(** Shorthand for List.hd *)
     80let head = List.hd
     81(** Shorthand for List.tail *)
     82let tail = List.tl
     83let just x = match x with
     84               Nothing -> assert false
     85             | Just s -> s
     86(** Given a hashtable, return all the keys as a list *)
     87let keys t = Hashtbl.fold (fun k d a -> k::a) t []
     88(** Given a hashtable, return all the values as a list *)
     89let values t = Hashtbl.fold (fun k d a -> d::a) t []
     90(** Copy one array into the other *)
     91let 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
    3994   items from the given list *)
    4095let rec combinations l =
    4196        match l with
    4297          []    -> []
    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 *)
    46101let wi_score c wi1 wi2 =
    47102        let scoretable = [ ((<=) 2,  1);
     
    58113        runtable scoretable;;
    59114
    60 (* given a configuration and a node, return the score. this is simply the sum of
     115(** Given a configuration and a node, return the score. this is simply the sum of
    61116   the scores of all the combinations of interfaces, written down as a fold for
    62117   efficiency *)
     
    64119        let foldfunc acc (wi1, wi2) = acc + (wi_score c wi1 wi2) in
    65120        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. *)
     125let score_configuration ns c =
    69126        let foldfunc acc n = acc + (node_score (Hashtbl.find c) n) in
    70127        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
     128        nodescores
     129
     130(** Given a filename, return a list of all the lines in the file with the given
    74131   filename *)
    75132let snarf_lines fname =
     
    83140        with End_of_file -> !result
    84141
    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. *)
     144let parse_pair nodename (wname, essid) =
     145        let new_wi = { wi_name = wname; wi_nodename = nodename; wi_essid = essid} in
    87146        let foo = try
    88                         let group = Hashtbl.find groups gname in
     147                        let group = Hashtbl.find groups essid in
    89148                        group.group_wis <- new_wi::group.group_wis;
    90149                  with Not_found ->
    91                         let group = { group_essid = gname; group_wis = [ new_wi ] } in
    92                         Hashtbl.add groups gname group in
     150                        let group = { group_essid = essid; group_wis = [ new_wi ] } in
     151                        Hashtbl.add groups essid group in
    93152        new_wi
    94153
     
    112171  the global 'groups' hash instead of getting it passed in from above, that
    113172  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);;
     173let 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 }
    127177
    128178let print_conf conf =
     
    149199        List.iter (do_fields $ (Str.split spacere)) (snarf_lines fname);;
    150200
    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 *)
     209let evolutionary_algorithm initialize recombine mutate evaluate select =
     210        let population = (evaluate $ initialize) () in
     211        let last_high_score = ref population.(0).score in
    157212        let iterations_since_new_high_score = ref 0 in
    158213        let generation = ref 0 in
    159214        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
    177220                if high_score > !last_high_score then begin
    178221                        last_high_score := high_score;
     
    188231                incr iterations_since_new_high_score;
    189232                incr generation
    190         done;
    191         print_conf population.(0);;
     233        done in
     234        population.(0);;
     235
     236let 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;;
    192261
    193262main
Note: See TracChangeset for help on using the changeset viewer.