In [1]:
import itertools
import random
from sympy import *
from sympy.abc import a,b,c,d
from matplotlib import pyplot as plt
import matplotlib as mpl
from deap import base, creator, tools
from deap.algorithms import eaSimple
import numpy as np
import random
np.set_printoptions(suppress=True)
mpl.rcParams['figure.figsize'] = (12.0, 16.0)
mpl.rcParams['font.size'] = 15
In [2]:
def calc_mult(input):
#input = [[a,b],[c,d]]
(a,b),(c,d) = input
return ((a*10 + b) * (c*10 + d))
In [3]:
def assign_optimal(nums):
sorted_nums = sorted(list(nums))
return [[sorted_nums[0],sorted_nums[2]],[sorted_nums[1],sorted_nums[3]]]
In [26]:
perms = list(itertools.permutations([0,1,2,3,4,5,6,7,8,9],4))
perms.sort(key = lambda p: calc_mult(assign_optimal(p)))
optimal = [calc_mult(assign_optimal(p)) for p in perms]
In [5]:
perms[0:10]
Out[5]:
In [6]:
def assign_random(nums):
nums = list(nums)
random.shuffle(nums)
return [nums[0:2],nums[2:4]]
In [7]:
def assign_low(nums,A,B,C,D):
assert len(nums) == 4
ones = []
tens = []
for num in nums:
#first number
if len(ones) + len(tens) == 0:
if num <= A:
tens.append(num)
else:
ones.append(num)
elif len(ones) + len(tens) == 1:
if len(ones) == 1:
if num <= B:
tens.append(num)
else:
ones.append(num)
else:
if num <= C:
tens.append(num)
else:
ones.append(num)
elif len(ones) + len(tens) == 2:
if len(ones) == 2:
tens.append(num)
elif len(tens) == 2:
ones.append(num)
else:
if num <= D:
tens.append(num)
else:
ones.append(num)
elif len(ones) + len(tens) == 3:
if len(ones) == 2:
tens.append(num)
else:
ones.append(num)
return list(zip(tens,ones))
In [35]:
def plot_performance(A,B,C,D):
optimal = [calc_mult(assign_optimal(p)) for p in perms]
strategy = [calc_mult(assign_low(p,A,B,C,D)) for p in perms]
random = [calc_mult(assign_random(p)) for p in perms]
f, (ax1, ax2) = plt.subplots(2, sharex=True)
ax2.plot(strategy, label='strategy')
#ax2.plot(random, label='random')
ax2.plot(optimal, label='optimal')
ax2.legend()
ax1.plot([s-o for s,o in zip(strategy,optimal)], label='strategy-optimal')
ax1.legend()
plt.show()
In [10]:
def generate_random_parameters():
return random.randint(0,9)
In [11]:
def mutate_parameters(individual, indpb):
for i in range(len(individual)):
if random.random() < indpb:
individual[i] = random.randint(0,9)
return individual,
In [12]:
def eval_parameters_sum(individual):
A,B,C,D = individual
return sum([calc_mult(assign_low(p,A,B,C,D)) for p in perms]),
In [14]:
def eval_parameters_dist_to_optimal_squared(individual):
A,B,C,D = individual
return sum([(s-o)**2 for s,o in zip([calc_mult(assign_low(p,A,B,C,D)) for p in perms],
optimal)]),
In [15]:
def stats_get_best_params(stats):
fit_values = [ind.fitness.values[0] for ind in stats]
index = fit_values.index(min(fit_values))
return stats[index]
In [20]:
def stats_get_num_unique_params(stats):
return len(set(tuple(ind) for ind in stats))
In [21]:
def genetic_search(eval_function,
population = 500,
hof_size = 5,
mating_prob = 0.3,
individual_mutate_prob = 0.3,
generations=20,
tournsize = 3):
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)
toolbox = base.Toolbox()
toolbox.register("param_int", generate_random_parameters)
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.param_int, n=4)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("evaluate", eval_function)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", mutate_parameters, indpb=individual_mutate_prob)
toolbox.register("select", tools.selTournament, tournsize=tournsize)
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean)
stats.register("min", np.min)
stats.register("max", np.max)
best_stats = tools.Statistics(lambda ind: ind)
best_stats.register("best", stats_get_best_params)
best_stats.register("uniq", stats_get_num_unique_params)
all_stats = tools.MultiStatistics(scores=stats, boards=best_stats)
pop = toolbox.population(n=population)
hof = tools.HallOfFame(hof_size)
pop, logbook = eaSimple(pop,
toolbox,
cxpb=mating_prob,
mutpb=individual_mutate_prob,
ngen=generations,
stats=all_stats,
halloffame=hof,
verbose=True)
return hof, pop, logbook
In [22]:
hof1, pop1, logbook1 = genetic_search(eval_parameters_sum)
In [36]:
plot_performance(*hof1.items[0])
In [29]:
hof3, pop3, logbook3 = genetic_search(eval_parameters_dist_to_optimal_squared)
In [38]:
plot_performance(*hof3.items[0])
In [ ]: