How to parallelize a while loop? - python

I am attempting to perform a value function iteration (for an Aiyagari model). The loop I am hoping to optimize is here (EDITED TO INCLUDE MWE):
beta = 0.95
r =0.03
a_lb = -1.5
a_ub = 10
y_l = 0.9
y_h = 1.1
yGrid = [y_l, y_h]
aSz = 100
nstates = 2
V0 = np.zeros((nstates, aSz))
V1 = np.zeros((nstates, aSz))
aPol = np.zeros((nstates, aSz))
Tol = 0.0001
Iter_max = 300
err = 1.0
PI = np.matrix([[0.5, 0.5],[0.09, 0.91]])
aGrid = np.linspace(a_lb, a_ub, num = aSz)
#
#
#
Iter = 0
while (err> Tol) and (Iter < Iter_max):
V0l= intp.interp1d(aGrid, V0[0,:])
V0h= intp.interp1d(aGrid, V0[1,:])
for a_today in range(aSz):
for yix in range(nstates):
def objective(a_tomorrow):
c = yGrid[yix] + (1+r)*aGrid[a_today] - a_tomorrow
exp_cont_Val = PI[yix,0] * V0l(a_tomorrow) + PI[yix,1] * V0h(a_tomorrow)
return -(-1/c + beta* exp_cont_Val)
minima_val = opt.fminbound(objective , a_lb, min(a_ub, yGrid[yix] + (1+r) *aGrid[a_today] -0.00001))
aPol[yix, a_today] = minima_val
V1[yix, a_today] = -objective(aPol[yix, a_today])
err = (abs(V1-V0)).max()
Iter = Iter+1
V0=V1.copy()
print('Iteration ' + str( Iter) + ' with error ' + str( err))
This is a part of a much bigger loop that uses a bisection method to find a value for a variable r.
First I guess an arbitrary value for r and use it to fill the values in the c array. From my testing, this first part of the loop is very fast. For the second part (given above) I think the opt.fminbound has the most overhead. I tried to use jit, but I kept getting error messages, I would appreciate any insight.

Related

When i try to print the mean and standard deviation, I am prompted with a name error: variable not defined

I am trying to print the mean and standard deviation however in its current form it doesnt recognize anything inside the loop. How would I go about correcting this to properly display what is intended. When i try to print the mean it says ex not defined.
import numpy as np
p = 0.44
q = 0.56
mu_1 = 26.5
sigma = 4.3
mu_2 = 76.4
n = 7
print( 'total number of jobs =', n)
lst_times = []
j = 0
def calc_avg_std(n):
while j < 100:
m = np.random.binomial(n,p)
easy_jobs = np.random.normal(mu_1,sigma,m)
n_chall = n-m
chall_jobs = np.random.exponential(mu_2,n_chall)
totalTime = sum(easy_jobs) + sum(chall_jobs)
lst_times.append(totalTime)
j = j + 1
ex = (mu_1 * p) + (mu_2 * q)
ex2 = (p *((mu_1**2)))+ (q*(mu_2**2)*2)
var = ex2-(ex**2)
stdev = np.sqrt(var)
return [ex , stdev]
print(' mean is',ex)
I tried this code without the def and return and runs properly but the professor insists that it should be implemented.
def is used to create a function. When you use return you return the values to the caller.
Replace your last prin witht the following lines:
call the function and keep the return values
print the returned values
mean, stdev = calc_avg_std(n)
print(mean)

Optimizing mathematical formula implementation with concatenations of summations

I'm trying to implement this following formula in Python. It's basically a long concatenation os summations, where an additional summation is added each time a new 'element' is needed. To simply explain the formula's structure, here's how this formula goes in order from 2 to 5 elements:
2 elements
3 elements
4 elements
5 elements
By the way, here's the g function shown in the formulas:
g function
Now, I foolishly tried coding this formula with my extremely barebones python programming skills. The initial goal was to try this with 15 elements, but given that it contained a lot of nested for loops and factorials, I quickly noticed that I could not really obtain a result from that.
At the end I ended up with this monstrous code, that would finish just after the heat death of the universe:
from ast import Str
import math
pNuevos = [0,2,2,2,2,1,1,1,2,2,2,1,2,2,1,1]
pTotales = [0,10,10,7,8,7,7,7,7,7,10,7,8,7,8,8]
def PTirada (personajes):
tirada = 0.05/personajes
return tirada
def Ppers1 (personajes, intentos):
p1pers = ((math.factorial(intentos-1)) / ((math.factorial(4))*(math.factorial(intentos-5)))) * (PTirada(personajes)**5) * ((1-PTirada(personajes))**(intentos-5))
return p1pers
def Ppers2 (personajes, intentos):
p2pers = 0
for i in range(10,intentos+1):
p2pers = p2pers + ( (math.factorial(intentos-1)) / ((math.factorial(4))*(math.factorial(i-5))*(math.factorial(intentos-i))) ) * (PTirada(personajes)**i) * ((1 - 2*(PTirada(personajes))) **(intentos-i))
p2pers = 2*p2pers
return p2pers
def Activate (z) :
probability1 = 0
probability2 = 0
probability3 = 0
probability4 = 0
probability5 = 0
probability6 = 0
probability7 = 0
probability8 = 0
probability9 = 0
probability10 = 0
probability11 = 0
probability12 = 0
probability13 = 0
probability14 = 0
for i in range (5*pNuevos[1], z-5*pNuevos[2]+1):
for j in range (5*pNuevos[2], z-i-5*pNuevos[3]+1):
for k in range (5*pNuevos[3], z-j-i-5*pNuevos[4]+1):
for l in range (5*pNuevos[4], z-k-j-i-5*pNuevos[5]+1):
for m in range (5*pNuevos[5], z-l-k-j-i-5*pNuevos[6]+1):
for n in range (5*pNuevos[6], z-m-l-k-j-i-5*pNuevos[7]+1):
for o in range (5*pNuevos[7], z-n-m-l-k-j-i-5*pNuevos[8]+1):
for p in range (5*pNuevos[8], z-o-n-m-l-k-j-i-5*pNuevos[9]+1):
for q in range (5*pNuevos[9], z-p-o-n-m-l-k-j-i-5*pNuevos[10]+1):
for r in range (5*pNuevos[10], z-q-p-o-n-m-l-k-j-i-5*pNuevos[11]+1):
for s in range (5*pNuevos[11], z-r-q-p-o-n-m-l-k-j-i-5*pNuevos[12]+1):
for t in range (5*pNuevos[12], z-s-r-q-p-o-n-m-l-k-j-i-5*pNuevos[13]+1):
for u in range (5*pNuevos[13], z-t-s-r-q-p-o-n-m-l-k-j-i-5*pNuevos[14]+1):
for v in range (5*pNuevos[14], z-u-t-s-r-q-p-o-n-m-l-k-j-i-5*pNuevos[15]+1):
probability14 = probability14 + eval("Ppers"+str(pNuevos[14])+"("+str(pTotales[14])+","+str(v)+")") * eval("Ppers"+str(pNuevos[15])+"("+str(pTotales[15])+","+str(z-v-u-t-s-r-q-p-o-n-m-l-k-j-i)+")")
probability13 = probability13 + eval("Ppers"+str(pNuevos[13])+"("+str(pTotales[13])+","+str(u)+")") * probability14
probability12 = probability12 + eval("Ppers"+str(pNuevos[12])+"("+str(pTotales[12])+","+str(t)+")") * probability13
probability11 = probability11 + eval("Ppers"+str(pNuevos[11])+"("+str(pTotales[11])+","+str(s)+")") * probability12
probability10 = probability10 + eval("Ppers"+str(pNuevos[10])+"("+str(pTotales[10])+","+str(r)+")") * probability11
probability9 = probability9 + eval("Ppers"+str(pNuevos[9])+"("+str(pTotales[9])+","+str(q)+")") * probability10
probability8 = probability8 + eval("Ppers"+str(pNuevos[8])+"("+str(pTotales[8])+","+str(p)+")") * probability9
probability7 = probability7 + eval("Ppers"+str(pNuevos[7])+"("+str(pTotales[7])+","+str(o)+")") * probability8
probability6 = probability6 + eval("Ppers"+str(pNuevos[6])+"("+str(pTotales[6])+","+str(n)+")") * probability7
probability5 = probability5 + eval("Ppers"+str(pNuevos[5])+"("+str(pTotales[5])+","+str(m)+")") * probability6
probability4 = probability4 + eval("Ppers"+str(pNuevos[4])+"("+str(pTotales[4])+","+str(l)+")") * probability5
probability3 += eval("Ppers"+str(pNuevos[3]) + "("+str(pTotales[3])+","+str(k)+")") * probability4
probability2 += eval("Ppers"+str(pNuevos[2]) + "("+str(pTotales[2])+","+str(j)+")") * probability3
probability1 += eval("Ppers"+str(pNuevos[1]) + "("+str(pTotales[1])+","+str(i)+")") * probability2
return probability1
print (str(Activate(700)))
Edit: Alright I think it would be helpful to explain a couple things:
-First of all, I was trying to find ways the code could run faster, as I'm aware the nested for loops are a performance hog. I was also hoping there would be a way to optimize so many factorial operations.
-Also, the P(A) function described in the g function represents the probability of an event happening, which is already in the code, in the first function from the top.
There's also the function f in the formula, which is just a simplification of the function g for specific cases.
The function f is the second function in the code, whereas g is the third function in the code.
I will try to find a way to simplify the multiple summations, and thanks for the tip of not using eval()!
I'm sorry again for not specifying the question more, and for that mess of code also.
I would expect to break it down with something like this:
def main():
A = 0.5
m = 10
result = g(A, m)
return
def sigma(k, m):
''' function to deal with the sum loop'''
for k in range(10, m+1):
# the bits in the formula
pass
return
def g(A, m):
''' function to deal with g '''
k=10
return 2 * sigma(k,m)
if __name__=='__main__':
''' This is executed when run from the command line '''
main()
Or alternatively to do similar with classes.
I expect you also need a function for p(A) and one for factorials.

How to structure python programs? Tried making it more structured, now runs 13 times slower

Im very new to programming, I wrote a simple program for a school project and wanted to make the code "prettier" by not just having the program be one giant function but instead be made up of multiple smaller functions with a singe purpose. I seemed to have messed up royally since the program now runs 13 times slower. How should I structured the program to make it run faster and just in general make programs easier to write, read and edit?
Here are the two programs:
First program (for reference values runs in ≈0:20):
import numpy as np
import matplotlib.pyplot as plt
def graf(a,b,H,p):
GM = 39.5216489684
x_0 = a + np.sqrt(a**2 - b**2)
v_0 = np.sqrt(GM*(2/x_0 - 1/a))
konstant_period = np.sqrt(a**3)*H
h = 1/H
'''starting position given by an elliptic orbit '''
stor_x_lista = [x_0]
stor_y_lista = [0]
hastighet_x = [0]
hastighet_y = [v_0]
liten_x_lista = []
liten_y_lista = []
''' a loop that approximates the points of the orbit'''
t = 0
tid_lista = []
n = 0
while n < konstant_period:
hastighet_x.append(hastighet_x[n] - h*GM* stor_x_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_x_lista.append(stor_x_lista[n] + h*hastighet_x[n])
hastighet_y.append(hastighet_y[n] - h*GM*stor_y_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_y_lista.append(stor_y_lista[n] + h*hastighet_y[n])
'''smaller list of points to run faster'''
if n % p == 0:
liten_x_lista.append(stor_x_lista[n])
liten_y_lista.append(stor_y_lista[n])
tid_lista.append(t)
n += 1
t += h
''' function that finds the angle'''
vinkel = []
siffra = 0
while siffra < len(liten_x_lista):
if liten_y_lista[siffra ] >= 0:
vinkel.append( np.arccos( liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2)))
siffra += 1
elif liten_y_lista[siffra] < 0 :
vinkel.append( np.pi + np.arccos( -liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2) ))
siffra += 1
'''get rid of line to find periodic function'''
mod_lista = []
modn = 0
while modn < len(vinkel):
mod_lista.append(vinkel[modn] - (2*np.pi*tid_lista[modn])/np.sqrt(a**3))
modn += 1
'''make all inputs have period 1'''
squeeze_tid = []
squeezen = 0
while squeezen < len(tid_lista):
squeeze_tid.append(tid_lista[squeezen]/np.sqrt(a**3))
squeezen += 1
del mod_lista[-1:]
del tid_lista[-1:]
del squeeze_tid[-1:]
plt.plot(squeeze_tid,mod_lista)
plt.title('p(t) där a = ' + str(a) + ' och b = ' + str(b))
plt.show
Second more split up program (for reference values runs in ≈4:20):
import numpy as np
import matplotlib.pyplot as plt
'''function that generates the points of the orbit'''
def punkt(a,b,H,p):
GM = 39.5216489684
x_0 = a + np.sqrt(a**2 - b**2)
v_0 = np.sqrt(GM*(2/x_0 - 1/a))
konstant_period = np.sqrt(a**3)*H
h = 1/H
'''starting position given by an elliptic orbit '''
stor_x_lista = [x_0]
stor_y_lista = [0]
hastighet_x = [0]
hastighet_y = [v_0]
liten_x_lista = []
liten_y_lista = []
''' a loop that approximates the points of the orbit'''
t = 0
tid_lista = []
n = 0
while n < konstant_period:
hastighet_x.append(hastighet_x[n] - h*GM* stor_x_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_x_lista.append(stor_x_lista[n] + h*hastighet_x[n])
hastighet_y.append(hastighet_y[n] - h*GM*stor_y_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_y_lista.append(stor_y_lista[n] + h*hastighet_y[n])
'''smaller list of points to run faster'''
if n % p == 0:
liten_x_lista.append(stor_x_lista[n])
liten_y_lista.append(stor_y_lista[n])
tid_lista.append(t)
n += 1
t += h
return (liten_x_lista,liten_y_lista,tid_lista)
''' function that finds the angle'''
def vinkel(a,b,H,p):
'''import lists'''
liten_x_lista = punkt(a,b,H,p)[0]
liten_y_lista = punkt(a,b,H,p)[1]
tid_lista = punkt(a,b,H,p)[2]
'''find the angle'''
vinkel_lista = []
siffra = 0
while siffra < len(liten_x_lista):
if liten_y_lista[siffra ] >= 0:
vinkel_lista.append( np.arccos( liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2)))
siffra += 1
elif liten_y_lista[siffra] < 0 :
vinkel_lista.append( np.pi + np.arccos( -liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2) ))
siffra += 1
return (vinkel_lista, tid_lista)
def periodisk(a,b,H,p):
'''import lists'''
tid_lista = vinkel(a,b,H,p)[1]
vinkel_lista = vinkel(a,b,H,p)[0]
'''get rid of linear line to find p(t)'''
mod_lista = []
modn = 0
while modn < len(vinkel_lista):
mod_lista.append((vinkel_lista[modn] - (2*np.pi*tid_lista[modn])/np.sqrt(a**3)))
modn += 1
'''make all inputs have period 1'''
squeeze_tid = []
squeezen = 0
while squeezen < len(tid_lista):
squeeze_tid.append(tid_lista[squeezen]/np.sqrt(a**3))
squeezen += 1
del mod_lista[-1:]
del tid_lista[-1:]
del squeeze_tid[-1:]
return (squeeze_tid,mod_lista)
'''fixa 3d-punkt av p(a,b) a är konstant b varierar??? '''
def hitta_amp(a):
x_b = []
y_b = []
n_b = 0.1
while n_b <= a:
x_b.append(n_b)
y_b.append(punkt(a,n_b,10**5,10**3))
return 0
def graf(a,b,H,p):
plt.plot(periodisk(a,b,H,p)[0],periodisk(a,b,H,p)[1])
plt.show
I would assume the thing that is going wrong is that the program is running the same, slow code multiple times instead of just running it once and then accessing the data. Is the problem that everything is done locally and nothing is stored globally or is it something else?
Just as a heads up, the only thing I know about programming is basic syntax, I have no clue how to actually write and run programs. I ran all the code in spyder if that affects anything.
plt.plot(periodisk(a,b,H,p)[0],periodisk(a,b,H,p)[1])
This code runs periodisk twice with the same arguments, thus at this point we know we run things at least 2 times slower.
You should do some_var = periodisk(a,b,H,p) and then some_var[0], some_var[1]. Or just use unpacking:
plt.plot(*periodisk(a,b,H,p))
tid_lista = vinkel(a,b,H,p)[1]
vinkel_lista = vinkel(a,b,H,p)[0]
Again doing the same thing twice (total: 4*time of (current) vinkel function). Again, smart assignment to fix this:
vinkel_lista, tid_lista = vinkel(a,b,H,p)
liten_x_lista = punkt(a,b,H,p)[0]
liten_y_lista = punkt(a,b,H,p)[1]
tid_lista = punkt(a,b,H,p)[2]
And now you repeat yourself thrice. (total: 12 * time of current punkt function)
liten_x_lista, liten_y_lista, tid_lista = punkt(a,b,H,p)
punkt function is like in original, so we arrived as total being 12 times slower - which quite matches your time estimations. :)
You are calling the functions once per returned list, you should only call them once.
When a method returns multiple variables, (e.g. punkt):
def punkt(a,b,H,p):
# Here is all your code
return (liten_x_lista,liten_y_lista,tid_lista)
You must be careful to only call the function once:
result = punkt(a,b,H,p)
liten_x_lista = result[0]
liten_y_lista = result[1]
tid_lista = result[2]
# As opposed to:
liten_x_lista = punkt(a,b,H,p)[0] # 1st call, ignoring results 2 and 3
liten_y_lista = punkt(a,b,H,p)[1] # 2nd call, ignoring results 1 and 3
tid_lista = punkt(a,b,H,p)[2] # 3rd call, ignoring results 1 and 2
Note: I would personally not return a list, but use python's unpacking:
def punkt(a,b,H,p):
# Here is all your code
return liten_x_lista, liten_y_lista, tid_lista
And you'd access it:
liten_x_lista, liten_y_lista, tid_lista = punkt(a,b,H,p)

Double Asterisk

I'm new to Python and really stumped on this. I'm reading from a book and the code works fine; I just don't get it!
T[i+1] = m*v[i+1]ˆ**/L
What's with the double asterisk part of this code? It's even followed by a forward slash. The variable L is initialized with the value 1.0 However, it looks like someone slumped over the keyboard, but the code works fine. Is this a math expression or something more? I would appreciate the help understanding this. Thanks!
full code:
from pylab import *
g = 9.8 # m/sˆ2
dt = 0.01 # s
time = 10.0 # s
v0 = 2.0 # s
D = 0.05 #
L = 1.0 # m
m = 0.5 # kg
# Numerical initialization
n = int(round(time/dt))
t = zeros(n,float)
s = zeros(n,float)
v = zeros(n,float)
T = zeros(n,float)
# Initial conditions
v[0] = v0
s[0] = 0.0
# Simulation loop
i = 0
while (i<n AND T[i]>=0.0):
t[i+1] = t[i] + dt
a = -D/m*v[i]*abs(v[i])-g*sin(s[i]/L)
v[i+1] = v[i] + a*dt
s[i+1] = s[i] + v[i+1]*dt
T[i+1] = m*v[i+1]ˆ**/L + m*g*cos(s[i+1]/L)
i = i + 1
This code is from the book "Elementary Mechanics Using Python: A Modern Course Combining Analytical and Numerical Techniques".
According to the formula on the page 255:
So the Python line should be:
T[i+1] = m*v[i+1]**2/L + m*g*cos(s[i+1]/L)
What's with the double asterisk part of this code?
The answer to your core questions (at least as it exists of this writing) is the double asterisk (star) is power -- "raise to the power". So, i**3 would be "cube i".
My (cross check) source: https://stackoverflow.com/a/1044866/18196

Loop gives correct output if script run in steps but not when skript runs from scratch

My script contains a while loop:
import numpy as np
ptf = 200 #profiltiefe
dz = 5
DsD0 = 0.02
D0 = 0.16 #cm2/sec bei 20°C
Ds= D0 * DsD0
eps= 0.3
R= 8.314
Ptot=101300
Te = 20
dt = 120
modellzeit = 86400*3
J=modellzeit/dt
PiA = 0.04
CA = PiA*1000/Ptot
respannual = 10 #t C ha-1 a-1
respmol = respannual/12*10**6/10000/(365*24)
respvol_SI = respmol * R * (Te+273)/(Ptot*3600)
respvol = respvol_SI * 100
I= ptf/dz
S = np.zeros(40)
for i in range(40):
if i <= 4:
S[i] = respvol/(2*4*dz)
if i > 4 and i <= 8:
S[i] = respvol/(4*4*dz)
if i > 8 and i <= 16:
S[i] = respvol/(8*4*dz)
Calt = np.repeat(CA,len(range(int(I+1))))
Cakt = Calt.copy()
res_out = range(1,int(J),1)
Cresult = np.array(Cakt)
faktor = dt*Ds/(dz*dz*eps)
timestep=0
#%%
while timestep <= J:
timestep = timestep+1
for ii in range(int(I)):
if ii == 0:
s1 = Calt[ii+1]
s2 = -3 * Calt[ii]
s3 = 2 * CA
elif ii == int(I-1):
s1 = 0
s2 = -1 * Calt[ii]
s3 = Calt[ii-1]
else:
s1 = Calt[ii+1]
s2 = -2 * Calt[ii]
s3 = Calt[ii-1]
result = Calt[ii]+S[ii]*dt/eps+faktor*(s1+s2+s3)
print(result)
Cakt[ii] = result
Cresult = np.vstack([Cresult,Cakt])
Calt = Cakt.copy()
What is intersting: If I run the complete script print(result) gives me different (and incorrect) values. But if I add all my constants before and run the loop part of the code (shown above) the loop performs well and delivers the output I want.
Any idea why this might happen?
I am on Python 2.7.5 / Mac OS X 10.9.1/ Spyder 2.
You are using python 2.7.5, so division of integers gives integer results. I suspect that is not what you want. For example, the term respannual/12 will be 0, so respmol is 0. Either change your constants to floating point values (e.g. respannual = 10.0), or add from __future__ import division at the top of your script.

Categories