Optimize with another variable - python

sorry i am a real beginner in Python and I really need help to understand this:
So basically I have a function who takes 4 arguments:
def expected_utility(p,y,x,q):
return p*u(y-x+q-premium(p,q), theta)+(1-p)*u(y-premium(p,q))
(premium and u are function already defined)
I already have the value of p(=0.2) and y(=1) and I need to find the optimal q's* for several x between 0.01 and 0.9.
This is my entire code I have done so far:
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
def premium(p,q):
return p*q
def u(z,theta):
return (z**(1+theta))/(1+theta)
def expected_utility(p,y,x,q):
return p*u(y-x+q-premium(p,q), theta)+(1-p)*u(y-premium(p,q))
theta=-2
y=1
p=0.2
N=100
x_array=np.linspace(0.01,0.9,N)
qs_optimal=np.empty(N)
And now I should create a loop for all x's in the x_array and use scipy.optimize.minimize_scalar to find all the optimals q's and store them in the qs_optimal array. How can I proceed? Thank you very very much for your help.

Related

Is it possible to vectorize scipy fsolve?

I know how to use fsolve in scipy
from scipy.optimize import fsolve
import numpy as np
k=4
def equations(p):
x,y=p
eq_1 = x+y-k
eq_2 = x-y
return (eq_1,eq_2)
fsolve(equations, (0,0))
But I don't know how to vectorize this function if k is a numpy array.
(I could do it in a loop for different value of k, but if will take a lot of time).
Is there a solution like :
from scipy.optimize import fsolve
import numpy as np
k=np.arange(10000)
def equations(p):
x,y=p
eq_1 = x+y-k
eq_2 = x-y
return (eq_1,eq_2)
fsolve(equations, (np.zeros(10000),np.zeros(10000)))
Thank's a lot if you have any idea
EDIT :
The link that some of you give below increases the calculation time as each line are not necessary independant.
For example, you can test those two code :
s=1000
#With array
t0=time.time()
k=np.arange(s)
def equations(p):
eq_1 = p**2-k
return (eq_1)
res=fsolve(equations, np.ones((s)))
print(time.time()-t0)
#With loop
t0=time.time()
res=np.zeros((s))
i=0
def equations(p):
eq_1 = p**2-i
return (eq_1)
while i<s:
res[i]=fsolve(equations, 1)[0]
i+=1
print(time.time()-t0)
Result
10.85175347328186
0.05588793754577637
Is there a way to avoid a loop but to keep a good speed with vectorize function
Not directly.
There is cython_optimize interface though, https://docs.scipy.org/doc/scipy/reference/optimize.cython_optimize.html
So you can drop to cython and implement the loops manually. YMMV though

How can I modify this differential equation solver to solve for a large number of variables?

I would like to modify the following code so that it can solve for thousands of variables with thousands of couple differential equations. The problem is that I would like to be able to import the variable list (y), ideally as a numpy array, but acceptably as a regular list. The list will be massive, so I don't want to define it in the function. If I do something like define a='n','c1',... and then set a=y, python complains that the variables are the wrong type. If I define a= n, c1,....python complains that I haven't defined the variables. If you have any advice on how to import the very large variable list for this function as a list or numpy array that would be great.
import numpy as np
from scipy.integrate import odeint
def kinetics(y,t,b1,b2):
n,c1=y
dydt=[(b1*n)+(b2*c1),(b1*n)-(c1)]
return dydt
b1=0.00662888
b2=0.000239997
n0=1
c1_0=1
y0=[n0,c1_0]
t = np.linspace(0, 10, 10)
sol = odeint(kinetics, y0, t, args=(b1,b2))
print(sol)
This sort of renaming and use of individual python objects for each step is likely to be slow, especially if you can use numpy array vectorization for parts of the computation. Note that your current code can be reformulated into a linear algebra problem which could be solved very efficiently using numpy, assuming this is true for the rest of the ODE structure. I warn against the path you want to take.
But, assuming that nothing can be vectorized in this way, and you want to continue down this path, you could define a class to store all your data and create an instance of said class with the current state of y at each function call. You could store the class definition in a separate python module to keep the problem definition tidy if needed.
If using python 3:
import numpy as np
from scipy.integrate import odeint
class vars:
def __init__(self, *args):
(self.n, self.c1) = args
def kinetics(y,t,b1,b2):
v = vars(*y)
dydt=[
(b1 * v.n) + (b2 * v.c1),
(b1 * v.n) - (v.c1)
]
return dydt
b1=0.00662888
b2=0.000239997
n0=1
c1_0=1
y0=[n0,c1_0]
t = np.linspace(0, 10, 10)
sol = odeint(kinetics, y0, t, args=(b1,b2))
print(sol)

ValueError: setting an array element with a sequence. Python

I am trying to solve a differential equation contains complex numbers. These complex numbers are constants A and B.
import numpy as np
import matplotlib.pyplot as plt
# intinialize values
x0=0
y0=1
xf=2
h=0.1
n=200
y=np.zeros([n])
t=np.zeros([n])
y[0]=y0
t[0]=x0
t=np.linspace(x0,xf,n)
gamma=1.0
width=1.0
v_g=1.0
L=1.0
k=1
r=1.0
C=1j
A=((8*np.pi)**(1.0/4.0)/(np.sqrt(width*L)))*(-
C/2*np.pi)*np.sqrt(gamma*v_g*L/2)
B=(k**2)+C*k*r-((width**2)*(r**2)/4)+r*v_g*t*(width**2/2)-v_g**2*t**2*
(width**2/4)+k**2/width**2
for i in range(1,n):
t[i]=t[i-1]+h
slope=A*np.exp(B)-(1/2)*(y[i-1])
y[i]=y[i-1]+h*slope
plt.plot(t,y,'-')
Can anyone help me to explain the problem and give a suggestion to solve the problem?

Plotting 2D integral function in python

Here is my first steps within the NumPy world.
As a matter of fact the target is plotting below 2-D function as a 3-D mesh:
N = \frac{n}{2\sigma\sqrt{\pi}}\exp^{-\frac{n^{2}x^{2}}{4\sigma^{2}}}
That could been done as a piece a cake in Matlab with below snippet:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
mu = 0;
sigma = sqrt(2)./n;
f = normcdf(x,mu,sigma);
mesh(x,n,f);
But the bloody result is ugly enough to drive me trying Python capabilities to generate scientific plots.
I searched something and found that the primary steps to hit above mark in Pyhton might be acquired by below snippet:
from matplotlib.patches import Polygon
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
sigma = 1
def integrand(x,n):
return (n/(2*sigma*np.sqrt(np.pi)))*np.exp(-(n**2*x**2)/(4*sigma**2))
t = np.linespace(0, 20, 0.01)
n = np.linespace(1, 100, 1)
lower_bound = -100000000000000000000 #-inf
upper_bound = t
tt, nn = np.meshgrid(t,n)
real_integral = quad(integrand(tt,nn), lower_bound, upper_bound)
Axes3D.plot_trisurf(real_integral, tt,nn)
Edit: With due attention to more investigations on Greg's advices, above code is the most updated snippet.
Here is the generated exception:
RuntimeError: infinity comparisons don't work for you
It is seemingly referring to the quad call...
Would you please helping me to handle this integrating-plotting problem?!...
Best
Just a few hints to get you in the right direction.
numpy.meshgrid can do the same as MatLABs function:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html
When you have x and n you can do math just like in matlab:
sigma = numpy.sqrt(2)/n
(in python multiplication/division is default index by index - no dot needed)
scipy has a lot more advanced functions, see for example How to calculate cumulative normal distribution in Python for a 1D case.
For plotting you can use matplotlibs pcolormesh:
import matplotlib.pyplot as plt
plt.pcolormesh(x,n,real_integral)
Hope this helps until someone can give you a more detailed answer.

While loops for lists?

I'm pretty new to programming and I have a quick question. I am trying to make a Gaussian function for a range of stars. However i want the size of undercurve be at 100 for all the stars. I was thinking of doing a while loop saying that while the total length of undercurve be 100. However, I get an error and I'm guessing it has something to do with it being a list. I'm showing you guys my code to see if you can help me out here. Thanks!
I get a syntax error: can't assign to call function
import numpy
import random
import math
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import scipy
from scipy import stats
from math import sqrt
from numpy import zeros
from numpy import numarray
variance = input("Input variance of the star:")
mean = input("Input mean of the star:")
space=numpy.linspace(-4,1,1000)
sigma = sqrt(variance)
Max = max(mlab.normpdf(space,mean,sigma))
normalized = (mlab.normpdf(space,mean,sigma))/Max
def random_y_pt():
return random.uniform(0,1)
def random_x_pt():
return random.uniform(-4,1)
import random
def undercurve(size):
result = []
for i in range(0,size):
y = random_y_pt()
x = random_x_pt()
if y < scipy.stats.norm(scale=variance,loc=mean).pdf(x):
result.append((x))
return result
size = 1
while len(undercurve(size)) < 100:
undercurve(size) = undercurve(1)+undercurve(size)
print undercurve(size)
plt.hist(undercurve(size),bins=20)
plt.show()
If your error is something like SyntaxError: can't assign to function call then that's because of your line
undercurve(size) = undercurve(1)+undercurve(size)
Which is trying to set the output of the right-hand side as the value of undercurve(size), which you cannot do.
It sounds like you actually want to see just the first 100 items in the list returned by undercurve(size). For that, use
undercurve(size)[:100]

Categories