Why my while loop failed (python)? - 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.

Related

How to perform a ranking selection in this Genetic Algorithm

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.

Function that calculates NPV from a list of cash flows

trying to write a function that will calculate present value of list of cash flows. I know that numpy can do this very easily but for an assignment I have to write my own function for this :/.
Here are the three cash flows in a list as well as discount rate.
cfList = [20, 50, 90]
r = 0.05
Here's the function i've written so far. f = 0 because I want to start with the first cash flow (in this case 20). i = 1 because for the first flow its raised to the 1st power and the second flow (50) will be squared and so on.
def npv(cfList, r):
f = 0
i = 1
pv = cfList[f] / ((1 + r) ** i)
while i < len(cfList):
f += 1
i += 1
return pv
print(npv(cfList, r))
However, this output only gives me the PV of the first cashflow, and not the sum of all three from the list. If you can help i appreciate it so much thanks !
You need to sum the individual cashflows within your function and return that. At the moment you are returning the value of pv of the first cashflow as you have a return statement in your for loop.
Also, I think the way you check your while loop against i will mean that you'll miss the last payment value. Usually you don't need to instantiate counter variables yourself (see my examples below):
def npv(cfList, r):
f = 0
i = 1
pv = cfList[f] / ((1 + r) ** i) # <-- this needs to be in the loop
while i < len(cfList): # <-- i will break loop before last payment is calculated.
f += 1
i += 1
return pv # <-- this return here is the issue
print(npv(cfList, r))
NPV being the sum of PV of all future cashflows, that is what you need to calculate. E.g.:
def npv(cfList, r):
sum_pv = 0 # <-- variable used to sum result
for i, pmt in enumerate(cfList, start=1): # <-- use of enumerate allows you to do away with the counter variables.
sum_pv += pmt / ((1 + r) ** i) # <-- add pv of one of the cash flows to the sum variable
return sum_pv # <-- only return the sum after your loop has completed.
Always remember that a return statement in a for-loop will break out of the loop the first time the return is encountered.
An alternate implementation would be to yield individual PVs from a PV generator and sum the results:
def pv_gen(cfList, r):
for i, pmt in enumerate(cfList, start=1):
yield pmt / ((1 + r) ** i)
print(sum(pv_gen(cfList, r)))
Returning the NPV of a list of cash flows would look like:
def npv(cfList, r):
return sum(f / ((1 + r) ** i) for i, f in enumerate(cfList, 1))
In []:
cfList = [20, 50, 90]
r = 0.05
npv(cfList, r)
Out[]:
142.14447683835436
If you're iterating across the list using the while loop, then you should have the action taking line of code within the while loop.
It also looks like your loop will be cutting early as i = 2 = len(cflist) on the second iteration (don't forget that python uses 0 based indexing) and because the return call is within the while loop.
This should work:
def npv(cfList, r):
f = 0
i = 1
pv = 0
while f <= len(cfList):
pv += (cfList[f] / ((1 + r) ** i))
f += 1
i += 1
return pv

Turtle Graphics window not responding

I am attempting to translate a Julia set generator that I made previously to Python code. However, when the code is run, the turtle graphics window stops responding immediately and draws nothing. Have I done something horribly wrong or is there something I'm missing? Perhaps I'm asking too much of python to do in 1 frame. Please explain what is causing this to happen and how I can fix it. Thanks!
import turtle
import time
y_set = []
map_output = 0
iterations = 0
#turtle.hideturtle()
#turtle.speed(1)
generate a list of y-values
def y_set (r):
global y_set
y_set = []
for n in range ((360*2)+1):
y_set.append(n)
create a color value
def color (i, n):
output = map(i, 2, 10000, 0, 2500)
if output < 0:
output = 0
if output > 0:
output = 255
iterate on the x's
def repeat (n, r, i):
global iterations
global x
global y
aa = 0
ba = 0
ab = 0
a = 0
b = 0
for j in range (n):
iterations += 1
aa = a * a
bb = b * b
ab = 2 * a * b
a = ((aa - bb) + float(r))
b = (ab + float(i))
if (ab + bb) > 4:
break
turtle.setx(100 * x)
turtle.sety(100 * y)
color(iterations, n)
turtle.pendown()
turtle.penup()
Iterate on the y's
def Julia (s, r, i, d):
global iterations
global y_set
global x
global y
global a
global b
y_set(s)
while len(y_set) > 0:
y = y_set[0]/360
del y_set[0]
x = -1.5
for n in range (round((700/(float(r)+1))+1)):
a = x
b = y
iterations = 0
repeat(10**d, r, i)
x += ((1/240)*s)
user input
real = input('Real: ')
imag = input('Imaginary: ')
Julia (1, real, imag, 100)
turtle.done()
There are too many problems with this code to focus on an algorithm error. When I try to run it, I get, TypeError: 'int' object is not iterable. Specific issues:
The i argument here is being passed a number:
iterations += 1
...
color(iterations, n)
...
def color(i, n):
output = map(i, 2, 10000, 0, 2500)
but Python's map function (and Julia's) expects a function as its first argument:
map(func, *iterables)
and it returns a list of the results of applying func to iterables but you treat the result as a scalar value:
output = map(i, 2, 10000, 0, 2500)
if output < 0:
output = 0
if output > 0:
output = 255
The color() function never uses its second argument, and never returns anything!
The variables a & b here are being treated as globals, set but not used, as if prepared for use by repeat():
global a
global b
...
a = x
b = y
iterations = 0
repeat(10 ** d, r, i)
but the a & b used by repeat() are locals initialized to zero:
a = 0
b = 0
You have a function and global variable with the same name y_set!
And your globals are out of control.

Programming Newton's method with backstepping in Python from Matlab Code

I am trying to code a Newton's Method with back stepping code that I wrote in Matlab to Python, but am having some trouble with the Python syntax. Matlab takes about 5 iterations, but my Python code is looping up to the max iteration of 1000 and having a domain error as the back stepping mechanism does not work (tries to calculate a negative log). I have not used Python in a while so I am most likely confusing some syntax of some sort.
Here is the Matlab code that works correctly:
x = 10; %defines x
f = #(x) log(x); %defines objective function
df = #(x) 1/x; %defines first derivative
tol = .00001; %defines our tolerance level
maxit = 1000; %defines maximum iteration steps
maxsteps = 200; %defines maximum backsteps
for i=1:maxit %starts loop
fval = f(x); %value of function at f(x)
fjac = df(x); %value of jacobian at f(x)
fnorm = norm(fval); %calculates norm value at fval
if fnorm<tol, return, end %if fnorm less than tol, end
x
d = -(fjac\fval); %forms second part of iteration rule
d
fnormold = inf; %sets arbitrary fnormold
for backstep=1:maxsteps
fvalnew = f(x+d); %calculates f(x+d)
fnormnew = norm(fvalnew); %calculates norm of fvalnew
if fnormnew<fnorm, break, end %implements 1st backstepping rule
if fnormold<fnormnew, d=2*d; break, end %implements 2nd backstepping rule
fnormold = fnormnew; %updates fnormold
d=d/2;
end
x=x+d;
end
disp(x)
Here is the Python code:
from math import log
x = 10
def f(x):
f = x* log(x)
return f
def df(x):
df = 1/x
return df
tol = .00001
maxit = 1000
maxsteps = 200
maxsteps = 200
for i in range(1, maxit):
fval = f(x)
fjac = df(x)
fnorm = abs(fval)
if fnorm < tol:
print x
d = -(fjac/fval)
fnormold = float('Inf')
for backstep in range(1, maxsteps):
fvalnew = f(x+d)
fnormnew = abs(fvalnew)
if fnormnew < fnorm:
break
if fnormold < fnormnew:
d= 2*d
break
fnormold = fnormnew
d = d/2
x = x+d
print x
1/x in df can be 0 in most cases since in python 2.x divison over integers returns integer
range based for is one index too less

Unknown numpy.optimize.fmin error

I am trying to write a program that calculates the optimum amount to bet based on log utility and simultaneous dependent events.
In order to do this I am trying to use the numpy.optimize.fmin function. The function anon that I am passing to it works and produces (hopefully) correct output but when numpy tries to optimise the function I get the following error
s[i].append(f[i][0]*w[i][0] + f[i][1]*w[i][1])
IndexError: invalid index to scalar variable.
Since I have no idea about fmin, I have no idea what is causing this error.
My code is below, hopefully not tl;dr but I wouldn't blame you.
APPENDIX
def main():
p = [[0.1,0.1,0.2, 0.2,0.1,0, 0.1,0.1,0.1]]
w = [[5,4]]
MaxLU(p,w,True)
def MaxLU(p, w, Push = False, maxIter = 10):
#Maximises LU, using Scipy in built function
if Push == True:
anon = lambda f: -PushLogUtility(p, w, f)
else:
anon = lambda f: -LogUtility(p, w, f)
#We use multiple random starts
f = []
LU = []
for i in range(0,maxIter):
start = np.random.rand(len(p))
start = start / 5 * np.sum(start)
f.append(optimize.fmin(anon, start)) #Error occurs in here!
if Push == True:
LU.append(PushLogUtility(p, w, f[-1]))
else:
LU.append(LogUtility(p, w, f[-1]))
#Now find the index of the max LU and return that same index of f
return f[LU.index(np.max(LU))]
def PushLogUtility(p,w,f):
#Outputs log utility incoroporating pushes and dependent totals, money data
#p : 9xk length vector of joint probabilities for each of the k games, p = [[p_(W_T W_M), p_(W_T P_M), p_(W_T L_M), p_(P_T W_M) ... ]]
#w : 2xk matrix of odds where w = [[total odds, money odds] ... ]
#f : 2xk matrix of bankroll percentages to bet, f = [[f_T, f_M] ... ]
utility = 0
k = len(p)
s = k*[[]]
for i in range(0,k):
s[i].append(f[i][0]*w[i][0] + f[i][1]*w[i][1])
s[i].append(f[i][0]*w[i][0])
s[i].append(f[i][0]*w[i][0] - f[i][1])
s[i].append(f[i][1]*w[i][1])
s[i].append(0)
s[i].append(-f[i][1])
s[i].append(-f[i][0] - f[i][1])
s[i].append(-f[i][0] - f[i][1])
s[i].append(-f[i][0] - f[i][1])
for i in range(0,9 ** k):
l = de2ni(i) #Converts number to base 9
if i == 0:
l += int(math.ceil(k - 1 - math.log(i + 1,9))) * [0]
else:
l += int(math.ceil(k - 1 - math.log(i,9))) * [0]
productTerm = np.prod([p[i][l[i]] for i in range(0,k)])
sumTerm = np.sum([s[i][l[i]] for i in range(0,k)])
utility = utility + productTerm * np.log(1 + sumTerm)
return utility
Here where you do:
s[i].append(f[i][0]*w[i][0] + f[i][1]*w[i][1])
if you look at the types, you'll find s[i] is a [], f[i] is 0.104528 and w[i] is [5,4]. You then try to index f[i] a second time - which is not possible and causes the error.

Categories

Resources