Commit 0caafc343500e2657f041a36f38f85e25b7dc581

Authored by Olav Kjartan Larseng
1 parent 8eca4f08

everything implemented, altough the fitness function is somewhat bad since the c…

…hromosomes is not going towards 0
__pycache__/chromsome.cpython-36.pyc
No preview for this file type
chromsome.py
... ... @@ -5,19 +5,58 @@ Created on Thu May 10 16:49:45 2018
5 5 @author: Olav
6 6 """
7 7 import numpy as np
  8 +from bitstring import BitArray
  9 +
  10 +xStart = 4.0
  11 +agentHeight = 0.2
  12 +upperLCorner = np.array([xStart-(agentHeight/2), agentHeight])
  13 +upperRCorner = np.array([xStart+(agentHeight/2), agentHeight])
  14 +lowerLCorner = np.array([xStart-(agentHeight/2), 0.0])
  15 +lowerRCorner = np.array([xStart+(agentHeight/2), 0.0])
8 16  
9 17 class Chromosome:
10 18 fitness = 0
11 19 gene = np.array
  20 + chromosomeBitsValue = 4
12 21  
13 22 def __init__(self, _gene):
14 23 self.gene = _gene
15 24  
16 25 def __repr__(self):
17   - return 'Gene: ' + str(self.gene) + ' Fitness: ' + str(self.fitness)
  26 + return 'Gene: ' + str(self.gene) + ' Fitness: ' + str(self.fitness) + "\n" + self.getCorners()
18 27  
19 28 def geneAt(self, index):
20 29 return self.gene[index]
21 30  
22 31 def geneSet(self, index, value):
23 32 self.gene[index] = value
  33 +
  34 + def getCorners(self):
  35 + x1 = float(BitArray(bin=''.join(map(str, self.gene[0:self.chromosomeBitsValue]))).uint)
  36 + y1 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue:self.chromosomeBitsValue*2]))).uint)
  37 +
  38 + x2 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*2:self.chromosomeBitsValue*3]))).uint)
  39 + y2 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*3:self.chromosomeBitsValue*4]))).uint)
  40 +
  41 + x3 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*4:self.chromosomeBitsValue*5]))).uint)
  42 + y3 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*5:self.chromosomeBitsValue*6]))).uint)
  43 +
  44 + x4 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*6:self.chromosomeBitsValue*7]))).uint)
  45 + y4 = float(BitArray(bin=''.join(map(str, self.gene[self.chromosomeBitsValue*7:self.chromosomeBitsValue*8]))).uint)
  46 +
  47 +
  48 + dx1 = x1 + upperLCorner[0]
  49 + dy1 = y1 + upperLCorner[1]
  50 +
  51 + dx2 = x2 + upperRCorner[0]
  52 + dy2 = y2 + upperRCorner[1]
  53 +
  54 + dx3 = x3 + lowerLCorner[0]
  55 + dy3 = y3 + lowerLCorner[1]
  56 +
  57 + dx4 = x4 + lowerRCorner[0]
  58 + dy4 = y4 + lowerRCorner[1]
  59 +
  60 + return 'x1: ' + str(dx1) + ' y1: ' + str(dy1) + ' x2: ' + str(dx2) + ' y2: ' + str(dy2) + ' x3: ' + str(dx3) + ' y3: ' + str(dy3) + ' x4: ' + str(dx4) + ' y4: ' + str(dy4)
  61 +
  62 +
24 63 \ No newline at end of file
... ...
... ... @@ -12,23 +12,40 @@ from chromsome import Chromosome
12 12 from bitstring import BitArray
13 13  
14 14 def fitnessCheckBounds(fitness, corners):
15   - reward = 10
16   - rewardAll = 100
  15 + reward = 100
  16 + rewardAll = 1000
17 17 allCornersInBound = True
18 18  
19 19 #print(corners)
20   - for corner in range(len(corners)):
21   - if corner >= 7:
22   - break
  20 + for pos in range(len(corners) - 1):
23 21  
24   - if corners[corner] >= xTo:
25   - fitness += reward
  22 + # Seeking the difference in x
  23 + diff = getDifferenceSide(corners[pos], xTo)
  24 + diff = round(diff, 2)
  25 + if diff == 0.00:
  26 + diff = 0.10
  27 + fitness += int((1/diff) * reward)
  28 +
  29 + # In bound of x
  30 + if corners[pos] <= xTo + agentHeight:
  31 + fitness += reward * 2
26 32 else:
  33 + fitness -= reward * 2
27 34 allCornersInBound = False
28 35  
29   - if corners[corner+1] >= yHeight:
30   - fitness += reward*2
  36 +
  37 + # Seeking the difference in y
  38 + diff = getDifferenceSide(corners[pos+1], yHeight)
  39 + diff = round(diff, 1)
  40 + if diff == 0.0:
  41 + diff = 0.1
  42 + fitness += int((1/diff) * reward * 10)
  43 +
  44 + # In bound of y
  45 + if corners[pos+1] >= yHeight:
  46 + fitness += reward * 20
31 47 else:
  48 + fitness -= reward * 20
32 49 allCornersInBound = False
33 50  
34 51  
... ... @@ -51,7 +68,7 @@ def fitnessCheckLeastEnergyJump(fitness, corners):
51 68 return fitness
52 69  
53 70 def fitnessCheckQuadrant(fitness, corners):
54   - reward = 100
  71 + reward = 10
55 72  
56 73 #Check length of all corners
57 74 sideLen1 = getSideLength(corners[0], corners[1], corners[2], corners[3])
... ... @@ -83,6 +100,8 @@ def fitnessCheckQuadrant(fitness, corners):
83 100  
84 101 fitness += (1/diff) * reward
85 102  
  103 +
  104 +
86 105 if allSidesEqual:
87 106 fitness += reward * 1000
88 107  
... ... @@ -138,38 +157,118 @@ def fitnessValue(chromosome):
138 157 def fitness(population):
139 158 l = list(population)
140 159 l.sort(key=lambda chromosome: fitnessValue(chromosome), reverse=True)
  160 + #totalFitness = getTotalFitness(l)
  161 + #for i in range(len(l)):
  162 + # l[i][0].fitness = round(l[i][0].fitness / totalFitness, 2)
  163 +
141 164 population = np.array(l)
142   -
143 165 return population
144 166  
145   -def mutation(population):
146   - """
147   - for i in range(len(population)):
148   - for j in range(len(population[i])):
  167 +
  168 +def getTotalFitness(populationList, numpy):
  169 + totalFitness = 0
  170 + for i in range(len(populationList)):
  171 + if numpy:
  172 + totalFitness += populationList[i][0].fitness
  173 + else:
  174 + totalFitness += populationList[i].fitness
  175 +
  176 + return totalFitness
  177 +
  178 +
  179 +def mutationWhole(population):
  180 + index = 0
  181 + for index in range(len(population)):
  182 + for j in range(len(population[index][0].gene)):
149 183 if random.uniform(0.0, 1.0) <= mutationRatio:
150   - if population[i][j] != 0:
151   - population[i][j] = 0
152   - else:
153   - population[i][j] = 1
154   - """
155   - chromosomePick = np.random.randint(len(population))
  184 + chromosome = population[index][0]
  185 + chromosomeBit = chromosome.geneAt(j)
  186 + if random.uniform(0.0, 1.0) <= mutationRatio:
  187 + if chromosomeBit != 0:
  188 + chromosome.geneSet(j, 0)
  189 + else:
  190 + chromosome.geneSet(j, 1)
  191 + return population
  192 +
  193 +def mutationSingle(population):
  194 + chromosomePick = roulette(population)
156 195 for j in range(populationSize):
157 196 if random.uniform(0.0, 1.0) <= mutationRatio:
158 197 chromosome = population[chromosomePick][0]
159 198 chromosomeBit = chromosome.geneAt(j)
  199 + if random.uniform(0.0, 1.0) <= mutationRatio:
  200 + if chromosomeBit != 0:
  201 + chromosome.geneSet(j, 0)
  202 + else:
  203 + chromosome.geneSet(j, 1)
160 204  
161   - if chromosomeBit != 0:
162   - chromosome.geneSet(j, 0)
163   - else:
164   - chromosome.geneSet(j, 1)
165   -
166   -
167 205 return population
168 206  
  207 +def mutation(population):
  208 + #population = mutationWhole(population)
  209 + population = mutationSingle(population)
  210 + return population
  211 +
  212 +# Using roulette based on the fittest population array, where fitness is sorted
  213 +# Chossing a random chromosome from a most likely group based on fitness
169 214 def roulette(population):
  215 + lp = list(population)
  216 + groupSize = 4
170 217 populationSize = len(population)
  218 + populationSlice = floor(populationSize / groupSize)
171 219  
172   - return population
  220 + randomPercentage = random.uniform(0.0, 1.0)
  221 + groupFitness = []
  222 + # Get total fitness of population
  223 + totalFitnessPopulation = getTotalFitness(lp, True)
  224 + if totalFitnessPopulation == 0:
  225 + return np.random.randint(populationSize)
  226 +
  227 +
  228 +
  229 + group = []
  230 + for i in range(0, groupSize):
  231 + group.append([])
  232 +
  233 + # Categorize them in groupSize groups
  234 + # Seems like redundant code, but couldn't find any better syntax,
  235 + # since I needed to insert the sliced[j][0] -> object and not the a numpy array
  236 + for i in range(groupSize):
  237 + if i != groupSize:
  238 + sliced = population[populationSlice*i:populationSlice*(i+1)]
  239 + for j in range(len(sliced)):
  240 + group[i].append(sliced[j][0])
  241 + else: #Just in case the len populationSize might be odd
  242 + sliced = population[populationSlice*i:len(populationSize)]
  243 + for j in range(len(sliced)):
  244 + group[i].append(sliced[j][0])
  245 +
  246 +
  247 +
  248 + # Get the total fitness for the groups
  249 + for i in range(groupSize):
  250 + groupFitness.append(round(getTotalFitness(group[i], False) / totalFitnessPopulation, 3))
  251 +
  252 + # This will make sure a chromosome is picked
  253 + # based on the likelyness of a group fitness
  254 + accPercentage = 0.00
  255 + for i in range(groupSize):
  256 + if accPercentage >= randomPercentage:
  257 + if i == 0:
  258 + return np.random.randint(0, len(group[i]))
  259 + else:
  260 + return np.random.randint(getAccumulatedLength2D(group, i-1), getAccumulatedLength2D(group, i))
  261 + else:
  262 + accPercentage = round(accPercentage + groupFitness[i], 3)
  263 +
  264 + # Should not happen but in the case
  265 + return np.random.randint(populationSize)
  266 +
  267 +def getAccumulatedLength2D(arr, index):
  268 + length = 0
  269 + for i in range(index):
  270 + length += len(arr[i])
  271 + return length
173 272  
174 273 def crossover(population):
175 274 #print("Before: \n" + str(population))
... ... @@ -181,6 +280,8 @@ def crossover(population):
181 280  
182 281 parent1 = population.item(i).gene
183 282 parent2 = population.item(i+1).gene
  283 + #parent1 = population.item(roulette(population)).gene
  284 + #parent2 = population.item(roulette(population)).gene
184 285  
185 286 #print('paren1' + str(parent1))
186 287 #print('paren2' + str(parent2))
... ... @@ -236,11 +337,11 @@ def crossover(population):
236 337  
237 338  
238 339  
239   -# Init agent values
  340 +# Init agent values, you'll have to change them in chromosome too
240 341 yHeight = 4.0
241   -xStart = 3.0
242   -xTo = 0.0
243   -agentHeight = 0.2
  342 +xStart = 4.0 # chromosome
  343 +xTo = 1.0
  344 +agentHeight = 0.2 #chromosome
244 345 upperLCorner = np.array([xStart-(agentHeight/2), agentHeight])
245 346 upperRCorner = np.array([xStart+(agentHeight/2), agentHeight])
246 347 lowerLCorner = np.array([xStart-(agentHeight/2), 0.0])
... ... @@ -251,9 +352,9 @@ lowerRCorner = np.array([xStart+(agentHeight/2), 0.0])
251 352 populationSize = 12
252 353  
253 354 # percentage of parents which will produce two childrens
254   -populationProduce = 0.5
  355 +populationProduce = 0.4
255 356  
256   -# WARNING: OLD below, not that relevant
  357 +# WARNING: OLD below, not that relevant. I am now using roulette to choose mates.
257 358 # Population production will determine how many chromosomes will be able to mate.
258 359 # The chromosomes are "cheating" on eachother so that we pick chromosome 0 - 1 to mate
259 360 # then 1 - 2, 2 - 3 and so on. Hence 100% populationProduce (see above) will yield a
... ... @@ -262,11 +363,11 @@ populationProduction = floor(ceil(populationSize * populationProduce)/2)
262 363 print('populationProduction ' + str(populationProduction))
263 364  
264 365 # How often a bit will flip during a mutation
265   -mutationRatio = 0.3
  366 +mutationRatio = 0.5
266 367 print('mutationRatio ' + str(mutationRatio))
267 368  
268 369 # How many interation of generations
269   -generationSize = 100
  370 +generationSize = 200
270 371  
271 372 # A value eg. x coordinate for a corner on a rectangle represents 4 bit value
272 373 chromosomeBitsValue = 4
... ... @@ -277,7 +378,6 @@ chromosomeBitsValue = 4
277 378 chromosomeSize = chromosomeBitsValue*2*4
278 379  
279 380 # Init random population
280   -#population = np.random.randint(2, size=(populationSize, chromosomeSize))
281 381 for i in range(populationSize):
282 382 chromosomeGene = np.random.randint(2, size=(chromosomeSize))
283 383 if i == 0:
... ... @@ -287,7 +387,8 @@ for i in range(populationSize):
287 387  
288 388  
289 389 # How many cycles until a mutation
290   -mutationCycle = 2
  390 +mutationCycle = 4
  391 +highestFitness = 0
291 392  
292 393 threshold = False
293 394 for generation in range(generationSize):
... ... @@ -305,15 +406,20 @@ for generation in range(generationSize):
305 406 for c in population:
306 407 numb += 1
307 408 print(c[0].fitness)
  409 + print(c[0].getCorners())
  410 +
  411 + if c[0].fitness > highestFitness:
  412 + highestFitness = c[0].fitness
  413 +
308 414 if numb == populationSize:
309 415 break
310 416  
311 417 #if fit >= 260:
312 418 # threshold = True
313 419  
  420 + print('highestFitness: ' + str(highestFitness))
314 421 if threshold:
315 422 break
316 423  
317   -
318 424  
319   -print(population)
  425 +#print(population)
... ...