source: genesis/nodes/channelga.py@ 1929

Last change on this file since 1929 was 1929, checked in by lodewijk, 21 years ago
  • .attic weg, ik neem aan dat dat een CVS artefact is
  • prutsen aan channelga.py
File size: 7.6 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 = {} # lijst van Node instanties
26groups = [] # lijst van Group instanties
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
37class Node:
38 def __init__(self, name, wis):
39 self.name = name
40 self.wis = wis
41 for wi in wis:
42 wi.setNode(self)
43 def wi_byname(self, name):
44 wi = filter(lambda wi: wi.name == name, self.wis)
45 assert len(wi) == 1
46 return wi[0]
47 def score(self):
48 score = 0
49 for i in range(len(self.wis)):
50 wi_i = self.wis[i]
51 if wi_i.group == None:
52 # orphaned interface
53 continue
54 if wi_i.group.channel == None:
55 print "huh?"
56 for j in range(len(self.wis)):
57 if i != j:
58 wi_j = self.wis[j]
59 if wi_j.group == None:
60 continue
61 diff = abs(wi_i.group.channel - wi_j.group.channel)
62 if diff > 2:
63 score = score + 1
64 else:
65 score = score - 1
66 score = score * len(self.wis)
67 return score
68
69class WI:
70 def __init__(self, name):
71 self.name = name
72 self.node = None
73 self.group = None
74 self.omni = 0
75 def setNode(self, node):
76 self.node = node
77 def setGroup(self, group):
78 self.group = group
79
80class WIGroup:
81 def __init__(self, name):
82 self.name = name
83 self.wis = []
84 self.channel = None
85 def add_wi(self, wi):
86 self.wis.append(wi)
87 wi.setGroup(self)
88
89class Configuration:
90 def __init__(self):
91 self.conf = None
92 self.calculated_score = None
93 def copy(self):
94 c = Configuration()
95 c.conf = self.conf[:]
96 c.calculated_score = None
97 return c
98 def randomize(self):
99 self.conf = [random.randint(1, 13) for i in range(len(groups))]
100 self.calculated_score = None
101 def score(self):
102 assert len(self.conf) == len(groups)
103 if self.calculated_score != None:
104 return self.calculated_score
105 for i in range(len(self.conf)):
106 groups[i].channel = self.conf[i]
107 score = 0
108 for node in nodes.values():
109 score = score + node.score()
110 self.calculated_score = score
111 return score
112 def mutate(self, rate):
113 for i in range(len(groups)):
114 if random.random() <= rate:
115 self.conf[i] = random.randint(1, 13)
116 def crossover(self, partner, numpoints):
117 # pick the crossover points
118 points = [random.randint(0, len(groups) - 1) for i in range(numpoints)]
119 points.sort()
120 conf = []
121 who = 0
122 lastpoint = 0
123 while len(points):
124 point = points.pop(0)
125 if who == 0:
126 l = self.conf[lastpoint:point]
127 who = 1
128 else:
129 l = partner.conf[lastpoint:point]
130 who = 0
131 conf.extend(l)
132 lastpoint = point
133 if who == 0:
134 l = self.conf[lastpoint:]
135 else:
136 l = partner.conf[lastpoint:]
137 conf.extend(l)
138 assert len(conf) == len(groups)
139 self.conf = conf
140
141
142# BEGIN UGLY PARSING CODE
143
144ipdict = {}
145ipnr_node = {}
146node_ipnr = {}
147node_links = {}
148
149def parse_wleiden_conf(lines):
150 ipnr = None
151 wi = None
152 peer = None
153 omni = 0
154 for l in lines:
155 if wi != None:
156 match = re.match("^\EW.*", l)
157 if match != None:
158 wi = None
159 ipnr = None
160 peer = None
161 continue
162 match = re.match("^SDESC=omni.*", l)
163 if match != None:
164 omni = 1
165 match = re.match("^IP=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*).*", l)
166 if match != None:
167 ipnr = match.group(1)
168 if not node_ipnr.has_key(nodename):
169 node_ipnr[nodename] = []
170 node_ipnr[nodename].append(ipnr)
171 ipnr_node[ipnr] = nodename
172 match = re.match("^POINT_TO_POINT=([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*).*", l)
173 if match != None:
174 peer = match.group(1)
175 if not node_links.has_key(nodename):
176 node_links[nodename] = []
177 node_links[nodename].append( (peer, wi) )
178 else:
179 match = re.match("^\$nodename='([^']*)';.*", l)
180 if match != None:
181 nodename = match.group(1).lower()
182 match = re.match("^\$config{'(wi[0-9]*).*", l)
183 if match != None:
184 wi = match.group(1)
185 omni = 0
186
187# gegeven een file met filenames van wleiden.conf's, parseer ze allemaal en
188# vul de datastructuren
189def parse_metafile(filename):
190 for fname in open(filename).readlines():
191 parse_wleiden_conf(open(fname[:-1]).readlines())
192 for nodename in node_ipnr.keys():
193 wis = []
194 if node_links.has_key(nodename):
195 d = {}
196 for peer, wi in node_links[nodename]:
197 if not d.has_key(wi):
198 wis.append(WI(wi))
199 d[wi] = 1
200 node = Node(nodename, wis)
201 nodes[nodename] = node
202
203 for nodename in node_links.keys():
204 node = nodes[nodename]
205
206 for peerip, winame in node_links[nodename]:
207 wi = node.wi_byname(winame)
208 if not ipnr_node.has_key(peerip):
209 print "Warning: node %s links to phantom IP %s" % (nodename, peerip)
210 continue
211 peername = ipnr_node[peerip]
212 bail = 0
213 for peerspeerip, peerswiname in node_links[peername]:
214 if not ipnr_node.has_key(peerspeerip):
215 print "Warning: node %s links to phantom IP %s" % (nodename, peerspeerip)
216 bail = 1
217 break
218 if ipnr_node[peerspeerip] == nodename:
219 break
220 if bail:
221 continue
222 peer = nodes[peername]
223 peerwi = peer.wi_byname(peerswiname)
224 # komt wi voor deze node al voor in de bestaande
225 # groepen?
226 group = None
227 for i in range(len(groups)):
228 if filter(lambda wi: wi.node.name == nodename and wi.name == winame, groups[i].wis) != []:
229 group = groups[i]
230 break
231 if group == None:
232 for i in range(len(groups)):
233 if filter(lambda wi: wi.node.name == peername and wi.name == peerswiname, groups[i].wis) != []:
234 group = groups[i]
235 break
236 if group == None:
237 # nee. maak een groep en voeg beide
238 # endpoints toe
239 group = WIGroup("group%d" % len(groups))
240 group.add_wi(wi)
241 groups.append(group)
242 group.add_wi(peerwi)
243 for group in groups:
244 group.wis = uniq(group.wis)
245
246# END UGLY PARSING CODE
247
248def plot_configuration(conf, out):
249 out.write("digraph plot {\n")
250 for i in range(len(groups)):
251 out.write("group%s [label=\"%d\"]\n" % (i, conf[i]))
252 for nodename in nodes.keys():
253 for wi in nodes[nodename].wis:
254 if wi.group == None:
255 continue
256 out.write("%s -> %s\n" % (nodename, wi.group.name))
257 out.write("}")
258
259parse_metafile('l')
260
261for i in range(20):
262 conf = Configuration()
263 conf.randomize()
264 population.append(conf)
265
266for iteration in range(1000):
267 for i in range(0, 9):
268 p = population[i].copy()
269 population[i].crossover(population[i + 10], random.randint(1, 4) * 2)
270 population[i + 10] = p
271 population[i + 10].mutate(0.05)
272 population.sort(lambda a, b: cmp(b.score(), a.score()))
273print population[0].score()
274plot_configuration(population[0].conf, open("foo.dot", 'w'))
275os.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')
276
Note: See TracBrowser for help on using the repository browser.