def test_create_sample_pop(self): logger.debug("HEFT makespan {0}".format(heft(self.wf).makespan)) pop = generate_population(self.wf, size=25, rng=self.rng, skip_limit=5) for soln in pop: self.assertEqual(soln.execution_order[-1].task.aft, soln.makespan) logger.debug("GA Initial Population") logger.debug("########################") for soln in pop: logger.debug(("Execution order: {0}".format(soln.execution_order))) logger.debug("Allocations: {0}".format( soln.list_all_allocations())) logger.debug("Makespan (s): {0}".format( calculate_fitness(['time'], soln))) logger.debug("Cost ($){0}".format(calculate_fitness(['cost'], soln))) soln.fitness = calculate_fitness(['time', 'cost'], soln) fig, ax = plt.subplots() ax.set_xlim([90, 200]) ax.set_ylim([100, 250]) x = [soln.fitness['time'] for soln in pop] y = [soln.fitness['cost'] for soln in pop] ax.scatter(x, y, c='red') ax.set_axisbelow(True) ax.legend() ax.grid(True) plt.xlabel('Solution Runtime') plt.ylabel('Solution execution cost') plt.show()
def ga(workflow, objectives, seed, mutation_probability, crossover_probability, generations=100, popsize=100): """ This function runs a standard genetic algorithm, with basic elitism, and basic diversification. The algorithm: * Generates a population of Solutions, based on the workflow provided * For a given number of generations: * Create a child population (newgen) * While the newgen < pop * Select parents using binary tournament seleciton * Crossover the parents to children * mutate the children * calculate the fitness of each child * add new children to newgen * Keep as many children as there are that outperform the parents :param mutation_probability: :param crossover_probability: :param workflow: :param objectives: :param seed: :param generations: :param popsize: :return: """ pop = generate_population(workflow, seed, generations, popsize) for soln in pop: soln.fitness = fitness.calculate_fitness(objectives, soln) # binary_tournament(pop) generation = 0 limit = False while generation < generations or limit: newgen = [] while len(newgen) > len(pop): p1 = binary_tournament(pop) p2 = binary_tournament(pop) c1, c2 = crossover(p1, p2, seed) for c in [c1, c2]: mutation(c) fitness.calculate_fitness(c, objectives) newgen.append(c) generation += 1 continue pass
def test_crossover(self): pop = generate_population(self.wf, size=25, rng=self.rng, skip_limit=5) for soln in pop: soln.fitness = calculate_fitness(['time', 'cost'], soln) random.seed(self.rng) p1 = binary_tournament(pop) self.assertSequenceEqual([0, 5, 3, 2, 1, 4, 7, 8, 6, 9], [t.task.tid for t in p1.execution_order]) p2 = binary_tournament(pop) self.assertSequenceEqual([0, 5, 4, 1, 3, 2, 8, 6, 7, 9], [t.task.tid for t in p2.execution_order]) c1, c2 = crossover(p1, p2, self.wf) p1order = [t.task.tid for t in p1.execution_order] c1order = [t.task.tid for t in c1.execution_order] self.assertSequenceEqual(p1order, c1order) for m in c1.machines: for allocation in c1.list_machine_allocations(m): if allocation.task.tid == 4: self.assertEqual('cat1_m1', allocation.machine.id) for m in c2.machines: for allocation in c2.list_machine_allocations(m): if allocation.task.tid == 4: self.assertEqual('cat0_m0', allocation.machine.id) self.assertNotEqual(p2.makespan, c2.makespan) fig, ax = plt.subplots() c1.fitness = calculate_fitness(['time', 'cost'], c1) c2.fitness = calculate_fitness(['time', 'cost'], c2) crossx = [c1.fitness['time'], c2.fitness['time']] crossy = [c1.fitness['cost'], c2.fitness['cost']] ax.scatter(crossx, crossy, c='green') x = [soln.fitness['time'] for soln in pop] y = [soln.fitness['cost'] for soln in pop] ax.grid(True) ax.set_xlim([90, 200]) ax.set_ylim([100, 170]) ax.scatter(x, y, c='red') ax.set_axisbelow(True) selectedx = [p1.fitness['time'], p2.fitness['time']] selectedy = [p1.fitness['cost'], p2.fitness['cost']] ax.scatter(selectedx, selectedy, c='blue') ax.legend() plt.xlabel('Solution Runtime') plt.ylabel('Solution execution cost') plt.show()
def test_binary_tournament(self): pop = generate_population(self.wf, size=25, rng=self.rng, skip_limit=5) for soln in pop: soln.fitness = calculate_fitness(['time', 'cost'], soln) compare_prob = 0.5 parent1 = binary_tournament(pop, compare_prob, self.rng) logger.debug(parent1.execution_order) compare_prob = 0.7 parent2 = binary_tournament(pop, compare_prob, self.rng) # parent2 = binary_tournament(pop, self.rng) logger.debug(parent2.execution_order) self.assertSequenceEqual([0, 5, 3, 4, 2, 1, 6, 8, 7, 9], [t.task.tid for t in parent1.execution_order]) logger.debug("Fitness: {0}".format(parent1.fitness)) self.assertSequenceEqual([0, 5, 4, 1, 3, 2, 8, 6, 7, 9], [t.task.tid for t in parent2.execution_order]) logger.debug("Fitness: {0}".format(parent2.fitness))
def test_mutation(self): pop = generate_population(self.wf, size=25, rng=self.rng, skip_limit=5) for soln in pop: soln.fitness = calculate_fitness(['time', 'cost'], soln) random.seed(self.rng) p1 = binary_tournament(pop, self.rng, 0.6) self.assertSequenceEqual([0, 5, 3, 2, 1, 4, 7, 8, 6, 9], [t.task.tid for t in p1.execution_order]) mutated_child = mutation(p1, self.wf, 'swapping', rng=self.rng) mutated_order_swapped = [0, 5, 3, 1, 7, 4, 2, 8, 6, 9] self.assertSequenceEqual( mutated_order_swapped, [alloc.task.tid for alloc in mutated_child.execution_order]) selected_machine = None for machine in mutated_child.machines: if machine.id == 'cat2_m2': selected_machine = machine mutated_alloc = mutated_child.list_machine_allocations( selected_machine) self.assertSequenceEqual([7, 2, 9], [alloc.task.tid for alloc in mutated_alloc])
def test_overall(self): total_generations = 25 crossover_probability = 0.5 mutation_probability = 0.4 popsize = 25 pop = generate_population(self.wf, size=popsize, rng=self.rng, skip_limit=5) for soln in pop: soln.fitness = calculate_fitness(['time', 'cost'], soln) generations = [] x = [soln.fitness['time'] for soln in pop] y = [soln.fitness['cost'] for soln in pop] weights = [200 * i for i in Counter(x).values() for j in range(i)] generations.append((x, y)) parents1 = [] parents2 = [] for gen in range(total_generations): new_pop = [] parent1 = None parent2 = None while len(new_pop) < len(pop): p1 = binary_tournament(pop, 0.5, self.rng) p2 = binary_tournament(pop, 0.5, self.rng) parent1 = p1 parent2 = p2 if random.random() < crossover_probability: c1, c2 = crossover(p1, p2, self.wf) new_pop.append(c1) new_pop.append(c2) elif random.random() < mutation_probability: c1 = mutation(p1, self.wf, 'swapping', rng=self.rng) if c1 is None: # The mutation didn't occur due to selection issue continue new_pop.append(c1) else: new_pop.append(p1) new_pop.append(p2) continue tmp_pop = pop + new_pop for soln in tmp_pop: soln.fitness = calculate_fitness(['time', 'cost'], soln) # soln.total_fitness = soln.calc_total_fitness() tmp_pop.sort(key=lambda x: (x.fitness['time'], x.fitness['cost'])) # tmp_pop.sort(key=lambda solution: solution.total_fitness) pop = tmp_pop[0:popsize] weights = [10 * i for i in Counter(x).values() for j in range(i)] x = [soln.fitness['time'] for soln in pop] y = [soln.fitness['cost'] for soln in pop] parent1_x = [parent1.fitness['time']] parent1_y = [parent1.fitness['cost']] parent2_x = [parent2.fitness['time']] parent2_y = [parent2.fitness['cost']] generations.append((x, y)) parents1.append((parent1_x, parent1_y)) parents2.append((parent2_x, parent2_y)) plt.draw() plt.show() for soln in pop: logger.info(soln.fitness) fig, ax = plt.subplots() ax.set_xlim([80, 250]) ax.set_ylim([100, 250]) scatter = ax.scatter(generations[0][0], generations[0][1], c='blue', alpha=.2, label='New Pop') parent_scatter = ax.scatter(parents1[0][0], parents1[0][1], c='red', alpha=0.8, label='Parent 1') parent2_scatter = ax.scatter(parents2[0][0], parents1[0][1], c='red', alpha=0.8, label='Parent 2') ax.legend() def animate(i): scatter.set_offsets(np.c_[generations[i][0], generations[i][1]]) parent_scatter.set_offsets(np.c_[parents1[i][0], parents1[i][1]]) parent2_scatter.set_offsets(np.c_[parents2[i][0], parents2[i][1]]) ax.set_xlabel('Runtime (s) \n Generation {0}'.format(i)) ax.set_ylabel('Cost ($)') anim = FuncAnimation(fig, animate, interval=100, frames=25) plt.draw() anim.save('filename.mp4', fps=1)