Created
March 15, 2015 17:28
-
-
Save juriad/3870b6851fb11d0d2a26 to your computer and use it in GitHub Desktop.
Skript na Evoluční robotiku
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from pylab import * | |
| from numpy import random | |
| from itertools import * | |
| def matrixCreate(rows, cols, mi=-1, ma=1): | |
| ''' | |
| Generates a matrix of size a x b filled with random numbers with uniform distribution in specified range. | |
| ''' | |
| return rand(rows, cols) * (ma - mi) + mi | |
| def fitness(population, axis=None): | |
| ''' | |
| Calculates mean in whole specified population. | |
| Change axis to 1 in order to calculate row-wise. | |
| ''' | |
| return mean(population, axis) | |
| def matrixPerturb(matrix, prob, mi=-1, ma=1): | |
| ''' | |
| Changes an element to a random one with certain probability. | |
| ''' | |
| out = array(matrix); | |
| for x in np.nditer(out, op_flags=['readwrite']): | |
| if rand() < prob: | |
| x[...] = rand() * (ma - mi) + mi | |
| return out | |
| def hillClimber(initialPopulation, fitnessFunc, probMutation): | |
| ''' | |
| Randomly changes the population. | |
| If the fitness gets better, accepts the change. | |
| ''' | |
| population = initialPopulation; | |
| fit = fitnessFunc(population) | |
| for gen in count(0): | |
| yield (gen, fit, population[0]) | |
| child = matrixPerturb(population, probMutation) | |
| childFit = fitnessFunc(child) | |
| if childFit > fit: | |
| population = child | |
| fit = childFit | |
| def tourSel(population, fitnessCached, probBetter): | |
| ''' | |
| Randomly selects two elements and compares them. | |
| The better one is returned with certain probability. | |
| ''' | |
| two = random.choice(population.shape[0], 2, False) | |
| fitA = fitnessCached[two[0]] | |
| fitB = fitnessCached[two[1]] | |
| return population[two[0] if (fitA > fitB) == (rand() < probBetter) else two[1]] | |
| def mutate(vector, probMutation, stdDev, mi=-1, ma=1): | |
| ''' | |
| Randomly mutates the vector each gene with certain probability. | |
| Change is a random number from normal distribution added to the original one. | |
| ''' | |
| out = array(vector); | |
| for i in range(vector.shape[0]): | |
| if rand() < probMutation: | |
| out[i] = max(min(vector[i] + randn() * stdDev, ma), mi) | |
| return out | |
| def crossover(first, second, probCrossover): | |
| ''' | |
| Crosses over the two vectors at random point with certain probability. | |
| ''' | |
| if rand() > probCrossover: | |
| return (first, second) | |
| out1 = array(first) | |
| out2 = array(second) | |
| point = randint(1, out1.shape[0]) | |
| for i in range(0, out1.shape[0]): | |
| out1[i] = first[i] if i < point else second[i] | |
| out2[i] = second[i] if i < point else first[i] | |
| return (out1, out2) | |
| def select(population, fitnessCached, probBetter): | |
| ''' | |
| Selects the better one out of two random ones with certain probability. | |
| ''' | |
| bestIndex = argmax(fitnessCached); | |
| rest = (tourSel(population, fitnessCached, probBetter) | |
| for i in range(population.shape[0] - 1)) | |
| return (population[bestIndex], rest) | |
| def pairwise(iterable): | |
| ''' | |
| s -> (s0,s1), (s2,s3), (s4, s5), ... | |
| ''' | |
| a = iter(iterable) | |
| return zip(a, a) | |
| def genAlg(initialPopulation, fitnessFunc, probBetter, probMutation, stdDev, probCrossover): | |
| ''' | |
| Generates a new population based on previous one by applying selection, crossing over and mutation. | |
| ''' | |
| population = initialPopulation; | |
| for gen in count(0): | |
| fitnessCached = fitnessFunc(population, 1) | |
| children = zeros(population.shape) | |
| best, rest = select(population, fitnessCached, probBetter) | |
| yield (gen, max(fitnessCached), best, population) | |
| children[0] = best | |
| crossed = (v | |
| for v1, v2 in pairwise(rest) | |
| for v in crossover(v1, v2, probCrossover)) | |
| mutated = (mutate(v, probMutation, stdDev) | |
| for v in crossed) | |
| for i, v in zip(count(1), mutated): | |
| children[i] = v | |
| population = children | |
| def countedCall(func): | |
| ''' | |
| Counts number of calls | |
| ''' | |
| counter = [0] | |
| def inner(*args): | |
| counter[0] += 1 | |
| return func(*args) | |
| return (inner, counter) | |
| def betterOf(n, initialSize, alg, fitnessFunc, *rest): | |
| ''' | |
| Runs n copies of alg in parallel and chooses the best one in population. | |
| ''' | |
| itersWithCounters = [(alg(matrixCreate(*initialSize), func, *rest), counter) | |
| for _ in range(n) | |
| for func, counter in [countedCall(fitnessFunc)]]; | |
| iters = [iwc[0] for iwc in itersWithCounters] | |
| counters = [iwc[1] for iwc in itersWithCounters] | |
| for generation in zip(*iters): | |
| g = max(generation, key=lambda x:x[1]) | |
| h = g[:3] + (sum(c[0] for c in counters),) + g[3:] | |
| yield h | |
| def showGeneProgress(result): | |
| ''' | |
| Show progress of gene values in time for previously defined algorithms | |
| ''' | |
| m = zeros((len(result), len(result[0][2]))) | |
| for gen, _, best, *_ in result: | |
| m[gen] = best | |
| imshow(transpose(m), cmap=cm.gray, aspect='auto', interpolation='nearest') | |
| xlabel("Generation") | |
| ylabel("Gene") | |
| show() | |
| def showFitnessProgress(*results): | |
| ''' | |
| Show progress of fitness in time for previously defined algorithms | |
| ''' | |
| for i, result in zip(count(1), results): | |
| n = len(result) | |
| x = zeros((n, 1)) | |
| y = zeros((n, 1)) | |
| for gen, fit, _, *_ in result: | |
| x[gen] = gen | |
| y[gen] = fit | |
| plot(x, y, label='Run {0}'.format(i)) | |
| xlabel("Generation") | |
| ylabel("Fitness") | |
| legend(loc='lower right') | |
| show() | |
| def usage(): | |
| print("p = list(takewhile(lambda x: x[1] < 0.9, betterOf(10, (15, 12), genAlg, fitness, 0.8, 0.05, 0.9, 0.7)))") | |
| print("p = list(takewhile(lambda x: x[1] < 0.9, betterOf(10, (1, 12), hillClimber, fitness, 0.05)))") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment