Package springbots :: Module evolvespringbot
[hide private]

Source Code for Module springbots.evolvespringbot

  1  """ 
  2  Springbot evolution extension. 
  3  Implements genetic operations like mutation and crossover 
  4  """ 
  5   
  6  from springbot import Springbot 
  7  from gear import Node, Spring 
  8  from random import choice, uniform, randint 
  9  from latimname import latimname 
 10  from math import sqrt, pi 
 11  from vector import Vector 
 12  from copy import copy 
 13   
 14  #: Keep track of the bloodline id being generated 
 15  _bloodline_count = 0 
 16   
 17  #: Separator string between bloodline ids in Springbot's bloodline field 
 18  BLOODLINE_SEP = ':' 
 19   
20 -class EvolveSpringbot(Springbot):
21 """ 22 Extends springbot to evolution methods 23 """ 24
25 - def __init__(self, parent=None, name="Unnamed", startangle=0, random=False):
26 27 global _bloodline_count 28 29 if random: 30 super(EvolveSpringbot, self).__init__(parent=random_springbot()) 31 else: 32 super(EvolveSpringbot, self).__init__(parent, name, startangle) 33 34 if not parent: 35 self['fitness'] = 0 36 self['bloodline'] = hex(_bloodline_count)[2:] + BLOODLINE_SEP 37 38 self._bloodline_count = 0 39 _bloodline_count += 1
40
41 - def generations(self):
42 """ 43 Return generations number 44 """ 45 return len(self['bloodline'].split(BLOODLINE_SEP)) - 1
46
47 - def addBloodline(self, parent):
48 """ 49 Adds a bloodline id 50 """ 51 self['bloodline'] += hex(parent._bloodline_count)[2:] + BLOODLINE_SEP 52 parent._bloodline_count += 1
53
54 - def crossover(self, other):
55 """ 56 Crosses this springbot with another one, returning a new one 57 """ 58 global _bloodline_count 59 60 # Create new springbot 61 breed = EvolveSpringbot() 62 63 # Breed springbots info 64 for key in self: 65 breed[key] = self[key] 66 67 breed['fitness'] = 0 68 breed['name'] = ' '.join(set(self['name'].split() + other['name'].split())) 69 breed['adapted'] = "random" 70 71 # Set bloodline 72 try: 73 breed['bloodline'] += 'X' + \ 74 other['bloodline'].split(BLOODLINE_SEP)[0] + '...' + other['bloodline'].split(BLOODLINE_SEP)[-2] + \ 75 BLOODLINE_SEP 76 except KeyError: 77 pass 78 79 # For each spring in self and other 80 for springA, springB in zip(self.springs + ([None] * ((len(other.springs)-len(self.springs))/2)), 81 other.springs + ([None] * ((len(self.springs)-len(other.springs))/2))): 82 83 if springA is None: springA = springB 84 elif springB is None: springB = springA 85 86 # Select spring 87 spring = choice([springA,springB]) 88 89 # Select node A 90 nodeA = breed.getNode(spring.a.id) 91 if nodeA is None: 92 nodeA = choice([self,other]).getNode(spring.a.id) 93 if nodeA is None: nodeA = spring.a 94 95 # Create node A 96 new_nodeA = Node(nodeA.pos, nodeA.vel, nodeA.acc) 97 new_nodeA.id = nodeA.id 98 nodeA = new_nodeA 99 100 # Add node A 101 breed.add(nodeA) 102 103 # Select node B 104 nodeB = breed.getNode(spring.b.id) 105 if nodeB is None: 106 nodeB = choice([self,other]).getNode(spring.b.id) 107 if nodeB is None: nodeB = spring.b 108 109 # Create node B 110 new_nodeB = Node(nodeB.pos, nodeB.vel, nodeB.acc) 111 new_nodeB.id = nodeB.id 112 nodeB = new_nodeB 113 114 # Add node B 115 breed.add(nodeB) 116 117 # Add created spring 118 breed.add(Spring(nodeA, nodeB, spring.amplitude, 119 spring.offset, spring.normal)) 120 121 # Remove unconnected elements 122 breed.removeUnconnected() 123 124 # Return new 125 return breed
126
127 - def mutate(self, newnodedist=100, nodevariation=10):
128 """ 129 Mutates a random structure of the springbot, which may be 130 adding or removing a node, adding or removing a spring, 131 changing any spring's parameter or changing a node position. 132 """ 133 # Tipos de mutacao: 134 # 0 - Adicao de node 135 # 1 - Remocao de node(se N > 1 e permanece conexo) 136 # 2 - Adicao de spring(se nao eh totalmente conexo) 137 # 3 - Remocao de spring(se permanece conexo) 138 # 4 - altera propriedades do spring 139 # 5 - muda posicao de node(e estica springs) 140 141 if len(self.nodes) == 0: 142 return 143 144 # Sorteia 145 tipo = choice(range(6)) 146 147 if tipo == 0: # 0 - Adicao de node 148 neigh = choice(self.nodes) 149 newnode = Node(pos=(neigh.pos.x + uniform(-newnodedist, newnodedist), 150 neigh.pos.y + uniform(-newnodedist, newnodedist))) 151 152 self.add(newnode) # Adiciona novo node 153 self.add(Spring(neigh, newnode, offset=uniform(0,pi*2))) # Adiciona nova spring 154 155 elif tipo == 1 and len(self.nodes) > 1: # 1 - Remocao de node(se N > 1 e permanece conexo) 156 157 # Cria uma copia do springbot 158 copia = Springbot() 159 copia.nodes = copy(self.nodes) 160 copia.springs = copy(self.springs) 161 162 # Escolhe um node para remover 163 toremove = choice(copia.nodes) 164 165 # Testa remocao na copia 166 copia.remove(toremove) 167 if not copia.unconnected(): 168 # OK, Continua conexo: pode remover do atual 169 for node in self.nodes: 170 if node.id == toremove.id: 171 self.remove(node) 172 break 173 174 elif tipo == 2 and len(self.nodes) > 1: # 2 - Adicao de spring(se nao eh totalmente conexo) 175 a = choice(self.nodes) 176 b = choice(self.nodes) 177 178 # Verifica se nao eh o mesmo 179 while a is b: 180 b = choice(self.nodes) 181 182 self.add(Spring(a, b, offset=uniform(0,pi*2))) # Adiciona nova spring 183 elif tipo == 3 and len(self.springs) > 0: # 3 - Remocao de spring(se permanece conexo) 184 185 # Escolhe spring 186 toremove = choice(self.springs) 187 188 # Remove 189 self.remove(toremove) 190 if self.unconnected(): 191 # Opa, nao eh mais conexo, volta atras: 192 self.add(toremove) 193 194 elif tipo == 4 and len(self.springs) > 0: # 4 - altera propriedades do spring 195 spring = choice(self.springs) 196 if choice([1, 2]) == 1: 197 spring.offset = max(spring.offset + uniform(-pi, pi), 0) 198 else: 199 added = uniform(-0.5, 0.5) 200 spring.amplitude = spring.amplitude + added if abs(spring.amplitude + added) <= 0.5 else spring.amplitude 201 202 elif tipo == 5: # 5 - muda posicao de node(e estica springs) 203 node = choice(self.nodes) 204 node.pos.x += uniform(-nodevariation,nodevariation) 205 node.pos.y += uniform(-nodevariation,nodevariation) 206 207 # Corrige springs 208 for spring in self.springs: 209 if spring.a is node or spring.b is node: 210 spring.normal = sqrt(sum((spring.a.pos-spring.b.pos)**2)) 211 212 # Returns itself 213 return self
214 215 # # 216 ################################################################################ 217 # # 218
219 -def random_springbot(nodes_num=10, springs_num=30, noderadius=100):
220 """ 221 Creates a new springbot totally random 222 """ 223 # Creates a new springbot 224 springbot = EvolveSpringbot(name=latimname(5)) 225 springbot["adapted"] = "random" 226 227 for x in xrange(randint(nodes_num/2, nodes_num)): 228 # Adiciona um node 229 newnode = Node(pos=(uniform(-noderadius, noderadius), 230 uniform(-noderadius, noderadius))) 231 springbot.add(newnode) # Adiciona novo node 232 233 if len(springbot.nodes) > 1: 234 for x in xrange(randint(springs_num/2, springs_num)): 235 # Adiciona uma spring aleatoria 236 a = choice(springbot.nodes) 237 b = choice(springbot.nodes) 238 239 # Verifica se nao eh o mesmo 240 while a is b: 241 b = choice(springbot.nodes) 242 243 # Adiciona nova spring 244 springbot.add(Spring(a, b, offset=uniform(0,pi*2), amplitude=uniform(-0.5, 0.5))) 245 246 # Remove unconnected elements 247 springbot.removeUnconnected() 248 249 return springbot
250 251 # # 252 ################################################################################ 253 # # 254