How to perform a ranking selection in this Genetic Algorithm - python

I'm building a Genetic Algorithm to maximize this function: x^5 - 10x^3 + 30x - y^2 + 21y.
The code must be in binary and the bounds for x and y are [-2.5, 2.5]. To generate the initial population I made a 16 bit string for both x and y where:
The first bit represents the signal [0 or 1]
The the second and third bit represents the integer part [00, 01 or 10]
The rest represents the float part
This is the function that generates the initial population:
def generate_population(n_pop):
population = list()
for _ in range(n_pop):
aux = list()
for _ in range(2):
signal = bin(randint(0, 1))[2:]
int_part = bin(randint(0, 2))[2:].zfill(2)
float_part = bin(randint(0, 5000))[2:].zfill(13)
aux.append((signal+int_part+float_part))
population.append(aux)
return population
I also made a function that returns the binary number into float:
def convert_float(individual):
float_num = list()
for i in range(2):
signal = int(individual[i][0])
int_part = int(individual[i][1:3], 2)
float_part = int(individual[i][3:], 2) * (10 ** -4)
value = round(int_part + float_part, 4)
if value > 2.5:
value = 2.5
if signal == 1:
value = value * (-1)
float_num.append(value)
return float_num
And lastly this function that calculate the fitness of each individual:
def get_fitness(individual):
x = individual[0]
y = individual[1]
return x ** 5 - 10 * x ** 3 + 30 * x - y ** 2 + 21 * y
This is my main function:
def ga(n_pop=10, n_iter=10):
population = generate_population(n_pop)
best_fitness_id, best_fitness = 0, get_fitness(convert_float(population[0]))
for i in range(n_iter):
float_population = [convert_float(x) for x in population]
fitness_population = [get_fitness(x) for x in float_population]
for j in range(n_pop):
if fitness_population[j] > best_fitness:
best_fitness_id, best_fitness = j, fitness_population[j]
print(f'--> NEW BEST FOUND AT GENERATION {i}:')
print(f'{float_population[j]} = {fitness_population[j]}')
selected_parents = rank_selection()
# childrens = list()
# childrens = childrens + population[best_fitness_id] # ELITE
After running the program I have something like this:
The population looks like: [['0000001100110111', '0000110111110101'], ['0010011111101110', '1000100101001001'], ...
The float population: [[0.0823, 0.3573], [1.203, -0.2377], ...
And the fitness values: [9.839066068044746, 16.15145434928624, ...
I need help to build the rank_selection() function, I've been stuck in this selection for 2 days. I know is something 1/N, 2/N etc and I've seen tons of examples in multiple languages but I could not apply any of them to this particular algorithm and it MUST be rank selecion.
I already know how to perform crossover and mutation.

Related

Returning a tuple containing the arithmetic mean and the unbiased sample variance

I have to write a function which takes a list of numbers of length ≥2, and returns a tuple containing the arithmetic mean and the unbiased sample variance of those numbers. i.e. given a list of items [𝑥1,𝑥2,…,𝑥𝑁], return a tuple (𝑚,𝑠2) where:
I'm not allowed to use inbuilt functions like sum, any math functions, etc. I'm not sure how to proceed without using those functions.
My code:
def mean_variance(numbers):
m = sum(numbers) / len(numbers)
var = sum((xi - m) ** 2 for xi in numbers) / len(numbers)
return m, var
What I'm testing on:
assert(mean_variance([1, 2, 3]) == (2, 1))
I dont know why you arent allowed to use inbuilt functions, but I guess you can do it without inbuilt functions like this:
def mean_variance(numbers):
meanSum = 0
for num in numbers:
meanSum += num
mean = meanSum / len(numbers)
varSum = 0
for num in numbers:
varSum += (num - mean) ** 2
var = varSum / (len(numbers) - 1)
return mean, var
I replaced the sum function with reduce and corrected an error in the formula.
Here is the code:
from functools import reduce
def mean_variance(numbers):
m = reduce(lambda x, y: x+y, numbers) / len(numbers)
var = reduce(lambda x, y: x+y, ((xi - m) ** 2 for xi in numbers)) / (len(numbers)-1)
return m, var
Without using any inbuilt methods
Mean and variance can come as floats.
so returning int or float will be automatically handled by assert
def mean_variance(inputList):
sum = 0
lenList = 0
for val in inputList:
sum = int(val) + sum
lenList = lenList + 1
mean = sum/lenList
sum_sq = 0
for val in inputList:
sq = (int(val) - int(mean)) ** 2
sum_sq = sum_sq + sq
variance = sum_sq/(lenList-1)
return (float(mean), float(variance))
print(mean_variance([1, 2, 3]))
assert mean_variance([1, 2, 3]) == (2, 1)

Need to reduce run time on creating a list of numbers based on a formula and a number n

Need a better way to create a list of numbers, so that the run time is less. Or probably figure out a better approach to my problem.
I'm running a code to create a series of numbers based on 2 formulas. Starting from 1, the formulas create the following numbers. The idea is to return the number n from the list that is created at the end. Even tough the formulas create the same number in some cases, only unique values remain, and the list is sorted to match. I use a while loop to create the list, and I believe that reducing the number of repetitions can help with my problem, but I can't figure out a way to effectively reduce it, without ruining the purpose of my code.
def dbl_linear(n):
x = 1
y = 0
z = 0
i = 0
u = []
u.append(x)
while i <= n:
x = (u)[i]
y = 2 * x + 1
u.append(y)
z = 3 * x + 1
u.append(z)
i = i + 1
u.sort()
uFix = set(u)
uFix = list(uFix)
uFix.sort()
return uFix[n]
print(dbl_linear(50))
These are the expected results. Which I get, but it takes too long.
dbl_linear(10), 22)
dbl_linear(20), 57)
dbl_linear(30), 91)
dbl_linear(50), 175)
Your function can be considerably simplified to:
Code:
def dbl_linear(n):
u = [1]
for i in range(n):
x = u[i]
u.extend((2 * x + 1, 3 * x + 1))
return sorted(set(u))[n]
Test Code:
assert dbl_linear(10) == 22
assert dbl_linear(20) == 57
assert dbl_linear(30) == 91
assert dbl_linear(50) == 175

Restricted integer partitions in Python

I want to find out how many ways there are to make 500 using only 1, 2, 5, 10, 20, 50, 100, and 200.
I understand that there exist greedy algorithms etc that can solve this type of question, but I want to be able to do it the following way:
The number of integer partitions of a given number, n, using only numbers from some set T, can be obtained from the coefficient of the xn term in the product of all (1-xt)-1, where t is in T.
To do this, note that the Taylor expansion of (1-xt)-1 equals (1+xt+x2t+...).
Here is the code I've written so far:
#################################
# First, define a function that returns the product of two
# polynomials. A list here
# represents a polynomial with the entry in a list corresponding to
# the coefficient of the power of x associated to that position, e.g.
# [1,2,3] = 1 + 2x + 3x^2.
#################################
def p(a,v):
"""(list,list) -> list"""
prodav = [0]*(len(a)+len(v)-1)
for n in range(len(a)):
for m in range(len(v)):
prodav[n+m] += v[m]*a[n]
return prodav
#################################
# Now, let a,b,c,...,h represent the first 501 terms in the Taylor
# expansion of 1/(1-x^n), where n gives the coin value, i.e
# 1,2,5,10,20,50,100,200 in pence. See the generating function
# section in https://en.wikipedia.org/wiki/Partition_(number_theory).
# Our function, p, multiplies all these polynomials together
# (when applied iteratively). As per the Wiki entry, the coefficient
# of x^t is equal to the number of possible ways t can be made,
# using only the denominations of change available, a so called
# 'restricted integer partition'. Note that it isn't necessary to
# consider the entire Taylor expansion since we only need the
# 500th power.
#################################
a = ( [1] ) * 501 # 1
b = ( [1] + [0] ) * 250 + [1] # 2
c = ( [1] + [0]*4 ) * 100 + [1] # 5
d = ( [1] + [0]*9 ) * 50 + [1] # 10
e = ( [1] + [0]*19 ) * 25 + [1] # 20
f = ( [1] + [0]*49 ) * 10 + [1] # 50
g = ( [1] + [0]*99 ) * 5 + [1] # 100
h = ( [1] + [0]*199 ) * 2 + [0]*101 # 200
x = p(h,p(g,p(f,p(e,p(d,p(c,p(b,a)))))))
print(x[500]) # = 6290871
My problem is that I'm not confident the answer this gives is correct. I've compared it to two other greedy algorithms whose outputs agree with each other, but not mine. Can anyone see where I might have gone wrong?

Why my while loop failed (python)?

I'm a new learner of python programming. Recently I'm trying to write a "tool" program of "dynamic programming" algorithm. However, the last part of my programe -- a while loop, failed to loop. the code is like
import numpy as np
beta, rho, B, M = 0.5, 0.9, 10, 5
S = range(B + M + 1) # State space = 0,...,B + M
Z = range(B + 1) # Shock space = 0,...,B
def U(c):
"Utility function."
return c**beta
def phi(z):
"Probability mass function, uniform distribution."
return 1.0 / len(Z) if 0 <= z <= B else 0
def Gamma(x):
"The correspondence of feasible actions."
return range(min(x, M) + 1)
def T(v):
"""An implementation of the Bellman operator.
Parameters: v is a sequence representing a function on S.
Returns: Tv, a list."""
Tv = []
for x in S:
# Compute the value of the objective function for each
# a in Gamma(x), and store the result in vals (n*m matrix)
vals = []
for a in Gamma(x):
y = U(x - a) + rho * sum(v[a + z]*phi(z) for z in Z)
# the place v comes into play, v is array for each state
vals.append(y)
# Store the maximum reward for this x in the list Tv
Tv.append(max(vals))
return Tv
# create initial value
def v_init():
v = []
for i in S:
val = []
for j in Gamma(i):
# deterministic
y = U(i-j)
val.append(y)
v.append(max(val))
return v
# Create an instance of value function
v = v_init()
# parameters
max_iter = 10000
tol = 0.0001
num_iter = 0
diff = 1.0
N = len(S)
# value iteration
value = np.empty([max_iter,N])
while (diff>=tol and num_iter<max_iter ):
v = T(v)
value[num_iter] = v
diff = np.abs(value[-1] - value[-2]).max()
num_iter = num_iter + 1
As you can see, the while loop at the bottom is used to iterate over "value function" and find the right answer. However, the while fails to loop, and just return num_iter=1. As for I know, the while loop "repeats a sequence of statements until some condition becomes false", clearly, this condition will not be satisfied until the diff converge to near 0
The major part of code works just fine, as far as I use the following for loop
value = np.empty([num_iter,N])
for x in range(num_iter):
v = T(v)
value[x] = v
diff = np.abs(value[-1] - value[-2]).max()
print(diff)
You define value as np.empty(...). That means that it is composed completely of zeros. The difference, therefore, between the last element and the second-to-last element will be zero. 0 is not >= 0.0001, so that expression will be False. Therefore, your loop breaks.

Random function with break command in Python

Write a function that accepts 3 numbers and calculates the average of the 3 numbers and raises the average to the second power (returns the average squared).
Write a loop that finds 3 random uniform numbers (0 to 1); sends the 3 numbers to the function and stops the loop when the value of the function is greater than 0.5625
I tried to figure out this 2 things but I am confused a little bit.
import random
a = random.random ()
b = random.random ()
c = random.random ()
def avenum(x1,x2,x3): # the average of the 3 numbers
z = (x1+x2+x3)/3.0
return z
y = avenum(a,b,c)
print 'the average of the 3 numbers = ',y
def avesec(x1,x2,x3): # the average of the second power
d = ((x1**2)+(x2**2)+(x3**2))/3.0
return d
y1 = avesec(a,b,c)
print 'the average of the second power = ',y1
The first question:
Write a function that accepts 3 numbers and calculates the average of the 3 numbers and raises the average to the second power (returns the average squared).
def square_of_average(x1, x2, x3):
z = (x1 + x2 + x3) / 3
return z ** 2 # This returns the square of the average
Your second question:
Write a loop that finds 3 random uniform numbers (0 to 1); sends the 3 numbers to the function and stops the loop when the value of the function is greater than 0.5625.
Assuming you want to write this in another function:
import random
def three_random_square_average():
z = 0 # initialize your answer
while(z <= 0.5625): # While the answer is less or equal than 0.5625...
# Generate three random numbers:
a, b, c = random.random(), random.random(), random.random()
# Assign the square of the average to your answer variable
z = square_of_average(a, b, c)
# When the loop exits, return the answer
return z
Another option:
import random
def three_random_squared_average():
while(True):
a, b, c = random.random(), random.random(), random.random()
z = square_of_average(a, b, c)
if(z > 0.5625):
break
return z
If you don't want a function:
import random
z = 0
while(z < 0.5625):
z = square_of_average(random.random(), random.random(), random.random())
print z
Firstly for 1) - you're raising the average to the second power... not each value. Otherwise you want the average of the second powers of the input values.
import random
a = random.random ()
b = random.random ()
c = random.random ()
def avenum1(x1,x2,x3): # the average of the 3 numbers
z = ((x1+x2+x3)/3.0)**2
return z
For 2): There are better ways but this is the most obvious.
def avenum1(x1,x2,x3): # the average of the 3 numbers
z = ((x1+x2+x3)/3.0)**2
return z
avg = 0:
while avg<0.5625:
a = random.random ()
b = random.random ()
c = random.random ()
avg = avenum1(a,b,c)
The better way:
avg = 0
while avg<0.5625:
list_ = [random.random() for i in range(3)]
avg = (sum(list_)/3.0)**2

Categories

Resources