source: genesis/nodes/channelga.py@ 1935

Last change on this file since 1935 was 1935, checked in by lodewijk, 21 years ago

wleiden.conf parseer code herschreven, is nu beter en simpeler

File size: 6.5 KB
Line 
1# experiment met een genetisch algoritme voor de kanalenplanning
2# het genetische zit er nu nauwelijks in, en wat er in zit is ongetwijfeld
3# fout. wat er wel goed in zit is het parseren van de bestaande situatie en
4# het scoren van (nu random) configuraties.
5
6# de score functie is nu redelijk simplistisch:
7# - de score van een combinatie van twee interfaces op een node is 1 als er
8# twee of meer kanalen tussen zitten, en -1 als dat niet zo is
9# - de score van een node is de som van de scores van alle combinaties van
10# interfaces van die node, maal het aantal interfaces. dat laatste omdat
11# een positieve score hebben knapper is met meer interfaces dan met minder,
12# dus dat moet beloond. een negatieve score is erger met meer interfaces
13# (belangrijker node, waarschijnlijk) dan met minder, dus dat moet
14# bestraft.
15# - de totale score is de som van de scores van de nodes
16#
17# het stukje "genetisch" aan het einde is afgeraffeld. mutation en
18# recombination gebeuren op de oplossing zelf ipv op een bitstring
19# representatie. selection is dom en neemt gewoon de helft beste oplossingen.
20import re
21import random
22import os
23
24# deze twee zijn nodig voor de evaluatie van een configuratie
25nodes = {} # nodename -> Node
26groups = {} # essid -> WIGroup
27
28population = []
29
30# gegeven een lijst, geef de lijst zonder dubbele elementen
31def uniq(l):
32 d = {}
33 for e in l:
34 d[e] = 1
35 return d.keys()
36
37def multiget(d, ks):
38 return map(lambda k: d[k], ks)
39
40class Node:
41 def __init__(self, name, wis):
42 self.name = name
43 self.wis = wis
44 for wi in wis:
45 wi.setNode(self)
46 def wi_byname(self, name):
47 wi = filter(lambda wi: wi.name == name, self.wis)
48 assert len(wi) == 1
49 return wi[0]
50 def score(self):
51 score = 0
52 for i in range(len(self.wis)):
53 wi_i = self.wis[i]
54 if wi_i.group == None:
55 # orphaned interface
56 continue
57 if wi_i.group.channel == None:
58 print "huh?"
59 for j in range(len(self.wis)):
60 if i != j:
61 wi_j = self.wis[j]
62 if wi_j.group == None:
63 continue
64 diff = abs(wi_i.group.channel - wi_j.group.channel)
65 if diff > 2:
66 score = score + 1
67 else:
68 score = score - 1
69 score = score * len(self.wis)
70 return score
71
72class WI:
73 def __init__(self, name):
74 self.name = name
75 self.node = None
76 self.group = None
77 self.omni = 0
78 def setNode(self, node):
79 self.node = node
80 def setGroup(self, group):
81 self.group = group
82
83class WIGroup:
84 def __init__(self, name):
85 self.name = name
86 self.wis = []
87 self.channel = None
88 def add_wi(self, wi):
89 self.wis.append(wi)
90 wi.setGroup(self)
91 def uniq(self):
92 self.wis = uniq(self.wis)
93
94class Configuration:
95 def __init__(self):
96 self.conf = None
97 self.calculated_score = None
98 def copy(self):
99 c = Configuration()
100 c.conf = self.conf.copy()
101 c.calculated_score = None
102 return c
103 def randomize(self):
104 self.conf = {}
105 for essid in groups.keys():
106 self.conf[essid] = random.randint(1, 13)
107 self.calculated_score = None
108 def score(self):
109 assert len(self.conf) == len(groups)
110 if self.calculated_score != None:
111 return self.calculated_score
112 for essid in groups.keys():
113 groups[essid].channel = self.conf[essid]
114 score = 0
115 for node in nodes.values():
116 score = score + node.score()
117 self.calculated_score = score
118 return score
119 def mutate(self, rate):
120 for essid in groups.keys():
121 if random.random() <= rate:
122 self.conf[essid] = random.randint(1, 13)
123 def crossover(self, partner, numpoints):
124 # pick the crossover points
125 essids = groups.keys()
126 points = [random.randint(0, len(essids) - 1) for i in range(numpoints)]
127 points.sort()
128 conf = []
129 who = 0
130 lastpoint = 0
131 while len(points):
132 point = points.pop(0)
133 if who == 0:
134 l = self.conf[lastpoint:point]
135 else:
136 l = partner.conf[lastpoint:point]
137 who = 1 - who
138 conf.extend(l)
139 lastpoint = point
140 if who == 0:
141 l = self.conf[lastpoint:]
142 else:
143 l = partner.conf[lastpoint:]
144 conf.extend(l)
145 assert len(conf) == len(groups)
146 self.conf = conf
147
148
149# BEGIN UGLY PARSING CODE
150
151to_resolve = [] # list of (essid, WI) tuples
152
153def parse_wleiden_conf(lines):
154 essid = None
155 wi = None
156 wis = []
157 for l in lines:
158 if wi != None:
159 match = re.match("^MODE=master.*", l)
160 if match != None:
161 master = 1
162 match = re.match("^ESSID=(.*)", l)
163 if match != None:
164 essid = match.group(1)
165 match = re.match("^EW[0-9]*", l)
166 if match != None:
167 if master == 1:
168 group = WIGroup(essid)
169 groups[essid] = group
170 group.add_wi(wi)
171 else:
172 # defer, may come way later
173 to_resolve.append( (essid, wi) )
174 master = 0
175 wi = None
176 essid = None
177 else:
178 match = re.match("^\$nodename='([^']*)';.*", l)
179 if match != None:
180 nodename = match.group(1).lower()
181 match = re.match("^\$config{'wi[0-9]*:[0-9].*", l)
182 if match != None:
183 continue
184 match = re.match("^\$config{'(wi[0-9]*).*", l)
185 if match != None:
186 wi = WI(match.group(1))
187 wis.append(wi)
188 master = 0
189 node = Node(nodename, wis)
190 nodes[nodename] = node
191
192# gegeven een file met filenames van wleiden.conf's, parseer ze allemaal en
193# vul de datastructuren
194def parse_metafile(filename):
195 for fname in open(filename).readlines():
196 parse_wleiden_conf(open(fname[:-1]).readlines())
197 for essid, wi in to_resolve:
198 if not groups.has_key(essid):
199 print "Warning: node %s, %s refers to unknown essid %s" % (wi.node.name, wi.name, essid)
200 continue
201 groups[essid].add_wi(wi)
202 for group in groups.values():
203 group.uniq()
204
205# END UGLY PARSING CODE
206
207def plot_configuration(conf, out):
208 out.write("digraph plot {\n")
209 for essid in groups:
210 out.write("\"%s\" [label=\"%s\\n(%d)\"]\n" % (essid, essid, groups[essid].channel))
211 for nodename in nodes.keys():
212 for wi in nodes[nodename].wis:
213 if wi.group == None:
214 continue
215 out.write("\"%s\" -> \"%s\"\n" % (nodename, wi.group.name))
216 out.write("}")
217
218parse_metafile('l')
219
220for essid in groups.keys():
221 print essid, map(lambda wi: wi.node.name, groups[essid].wis)
222
223for i in range(20):
224 conf = Configuration()
225 conf.randomize()
226 population.append(conf)
227
228for iteration in range(1000):
229 for i in range(0, 9):
230 p = population[i].copy()
231 #population[i].crossover(population[i + 10], random.randint(1, 4) * 2)
232 population[i + 10] = p
233 population[i + 10].mutate(0.05)
234 population.sort(lambda a, b: cmp(b.score(), a.score()))
235 print population[0].score(), map(lambda g: g.channel, groups.values())
236plot_configuration(population[0].conf, open("foo.dot", 'w'))
237os.system('neato -Gstart=foo -Goverlap=false/scale -Gsplines=true -Gsep=2 -Gratio=fill -Gnslimit=50.0 -Grotate=90 -Gsize="11,7.5" -Tps -o channelga.ps foo.dot')
238
Note: See TracBrowser for help on using the repository browser.