I kept getting the error only length-1 arrays can be converted to Python scalars. Most people suggest sometimes numpy is not compatible with other existing math functions. but I changed every math function to np functions.
The error states:
Traceback (most recent call last): File "/Users/jimmy/Documents/2.py", line 20, in <module>
eu = mc_simulation(89,102,0.5,0.03,0.3,1000) File "/Users/jimmy/Documents/2.py", line 12, in mc_simulation
ST = s0 * exp((r - 0.5 * sigma ** 2) * T + sigma * a * z) TypeError: only length-1 arrays can be converted to Python scalars
My code:
from numpy import *
import numpy as np
from math import exp
def mc_simulation(s0, K, T, r, sigma, no_t):
random.seed(1000)
z = random.standard_normal(no_t)
ST = s0 * exp((r - 0.5 * sigma ** 2) * T + sigma * np.sqrt(T) * z)
payoff = maximum(ST - K, 0)
eu_call = exp(-r * T) * sum(payoff) / no_t
return eu_call
eu = mc_simulation(89,102,0.5,0.03,0.3,1000)
You don't need math here. Use numpy.exp. Furthermore, consider getting into the habit of not using the * operator with imports.
import numpy as np
np.random.seed(1000)
def mc_simulation(s0, K, T, r, sigma, no_t):
z = np.random.standard_normal(no_t)
ST = s0 * np.exp((r - 0.5 * sigma ** 2) * T + sigma * np.sqrt(T) * z)
payoff = np.maximum(ST - K, 0)
eu_call = np.exp(-r * T) * np.sum(payoff) / no_t
return eu_call
print(mc_simulation(89,102,0.5,0.03,0.3,1000))
3.4054951916465099
To your comment of "why shouldn't I use the * operator": there are a ton of good discussions on why this can create trouble. But here is what the official documentation has to say on that: when you use from numpy import *:
This imports all names except those beginning with an underscore (_).
In most cases Python programmers do not use this facility since it
introduces an unknown set of names into the interpreter, possibly
hiding some things you have already defined.
Your own example illustrates that. If you were to use:
from numpy import *
from math import *
Both have an exp function that gets imported into the namespace as exp. Python might then have trouble knowing which exp you want to use and, as you saw here, they are quite different. The same applies if you have already defined an exp function yourself, or any other function that shares a name with any in those two packages.
In general, be wary of any tutorials you run across that use from x import * consistently.
Related
I am trying to optimize my code with numba.
I designed the code to contain a gl.py file which contains some arrays which will be used by main.py and functions called inside main() from main.py.
The auxiliary.py looks like:
import numpy as np
from numba import jit, types
from cmath import sqrt, exp, sin
N_timesteps_imag = 100
N_epsilon_divs = 60
N_z_divs = 2000
K = N_z_divs # equal to the variable N_z_divs
delta_epsilon = 0.1
delta_z = 0.1
lambd = 1.5
z_max = (N_z_divs/2) * delta_z
epsilon_range = np.linspace(0.0, N_epsilon_divs*delta_epsilon, N_epsilon_divs+1)
z_range = np.linspace(-z_max, z_max, N_z_divs+1)
psi_ground = np.zeros((N_z_divs+1, N_epsilon_divs+1, N_timesteps_imag+1), dtype=types.complex128)
#jit(nopython=True)
def pop_psiground_t0():
for c1 in range(1, psi_ground.shape[0]-1):
for c2 in range(1, psi_ground.shape[1]-1):
zed = (c1 - N_z_divs/2) * delta_z
epsi = c2 * delta_epsilon
psi_ground[c1, c2, 0] = sqrt(3) * epsi * exp(-sqrt(epsi**(2*lambd) + zed**2))
pop_psiground_t0()
The main.py looks like (MWE):
import numpy as np
import auxiliary
def main():
print(auxiliary.psi_ground[1000, 40, 0]) # shall NOT be 0 + 0j !!!
if __name__ == '__main__':
main()
Irrespective to what I put for the keyword argument dtype for the declaration of psi_ground inside auxiliary.py, be it numba.types.complex128, np.complex128, np.clongdouble, nothing works.
In particular, for np.complex128, I get the following error when running python3 main.py:
No implementation of function Function(<built-in function setitem>) found for signature:
>>> setitem(readonly array(complex128, 3d, C), Tuple(int64, int64, Literal[int](0)), complex128)
There are 16 candidate implementations:
- Of which 14 did not match due to:
Overload of function 'setitem': File: <numerous>: Line N/A.
With argument(s): '(readonly array(complex128, 3d, C), UniTuple(int64 x 3), complex128)':
No match.
- Of which 2 did not match due to:
Overload in function 'SetItemBuffer.generic': File: numba/core/typing/arraydecl.py: Line 171.
With argument(s): '(readonly array(complex128, 3d, C), UniTuple(int64 x 3), complex128)':
Rejected as the implementation raised a specific error:
TypeError: Cannot modify value of type readonly array(complex128, 3d, C)
raised from /home/velenos14/.local/lib/python3.8/site-packages/numba/core/typing/arraydecl.py:177
During: typing of setitem at /mnt/c/Users/iusti/Desktop/test_python/auxiliary.py (45)
File "auxiliary.py", line 45:
def pop_psiground_t0():
<source elided>
epsi = c2 * delta_epsilon
psi_ground[c1, c2, 0] = sqrt(3) * epsi * exp(-sqrt(epsi**(2*lambd) + zed**2))
How can I proceed with this? I tried to follow what it's written here: numba TypingError with complex numpy array and native data types
And yes, I need that psi_ground array to be of complex type, with a lot of precision, even if initially it's populated by real numbers. Later in the main() will get re-populated by complex numbers. Thank you!
psi_ground = np.zeros((N_z_divs+1, N_epsilon_divs+1, N_timesteps_imag+1), dtype=types.complex128)
must be defined inside numba function. The error clearly states that numba is unable to change the values of the psi_ground array.
Below is the modified code
import numpy as np
from numba import jit, types
from cmath import sqrt, exp, sin
N_timesteps_imag = 100
N_epsilon_divs = 60
N_z_divs = 2000
K = N_z_divs # equal to the variable N_z_divs
delta_epsilon = 0.1
delta_z = 0.1
lambd = 1.5
z_max = (N_z_divs/2) * delta_z
epsilon_range = np.linspace(0.0, N_epsilon_divs*delta_epsilon, N_epsilon_divs+1)
z_range = np.linspace(-z_max, z_max, N_z_divs+1)
#jit(nopython=True)
def pop_psiground_t0():
psi_ground = np.zeros((N_z_divs+1, N_epsilon_divs+1, N_timesteps_imag+1), dtype=types.complex128)
for c1 in range(1, psi_ground.shape[0]-1):
for c2 in range(1, psi_ground.shape[1]-1):
zed = (c1 - N_z_divs/2) * delta_z
epsi = c2 * delta_epsilon
psi_ground[c1, c2, 0] = sqrt(3) * epsi * exp(-sqrt(epsi**(2*lambd) + zed**2))
pop_psiground_t0()
I've tried a few formats and ideas, but the syntax is kind of confusing. Help is appreciated, danke.
Only with python built-in functios:
import math
r = math.e**(math.cos(theta)) - 2 * math.cos(4 * theta) + math.sin(theta/12)**5
With Sympy(for symbolic computation):
from sympy import Symbol, cos, sin, E
t = Symbol('Θ')
E**(cos(t)) - 2 * cos(4 * t) + sin(t/12)**5
Result:
from math import exp, cos, sin
theta = 0.1 # Just as an example
r = exp(cos(theta)) - 2 * cos(4 * theta) + sin(theta / 12) ** 5
How about something like this?
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(-2*np.pi, 2*np.pi, 10)
r = np.exp(np.cos(theta)) - 2*np.cos(4*theta) + np.sin(theta/12)**5
plt.plot(theta,r)
plt.savefig('parametric.jpg')
A very straightforward, but naive approach would be to just use the math library, which is a standard library in python.
import math
def r(theta):
return math.pow(math.e, math.cos(theta)) - 2 * math.cos(4*theta) + math.pow(math.sin(theta/12), 5)
better results are possible with libraries for scientific computing, like numpy or other members of the scipy ecosystem.
I want to do a plot of this equation below:
Problem 1: You see... since my function is a function of ν I have to calculate my integral to each ν in my domain. My question is: what is the best way to do that?
I thought about using scipy to do the integral and a for loop to calculate it several times to each ν, but it seems a very inelegant way to solve my problem. Does someone know a better alternative? Does someone have a different idea?
Problem 2: When I write my code I get some errors, mainly because I think that the exponential has a very small expoent. Do you have any ideas of how should I change it so I can do this plot using Python?
Oh, if you try with a different method, it is supposed to look like this
Here is the code I was working on. I'm coming back to Python now, so maybe there is some errors. The plot I'm getting is very different from the one that this is supposed to look.
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
def luminosity_integral(r, x):
T_est = 4000
R_est = 2.5 * (696.34*1e6)
Temp = ((2/(3*pi))**(1/4)) * T_est * ((R_est/r)**(3/4))
termo1 = ((4 * (pi**2) * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*Temp))
return ((termo1 * r ) / (np.exp(termo2) - 1))
freqs = np.linspace(1e10, 1e16)
y = np.array([])
for i in freqs:
I = quad(luminosity_integral, (6 * 2.5 * (696.34*1e6)), (7e4 * 2.5 * (696.34*1e6)), args = (i))
temp = np.array([I[0]])
y = np.concatenate((y, temp))
plt.loglog(freqs, y)
plt.show()
Reuse the term R_est instead instead of writing its expression 3 times (better if you want to change that parameter).
you used a pi**2 in the constant multiplying the integral (don't affect the shape)
The shape resembles what you put as reference, but not in the suggested range.
You are using the value of T as T_*, are you sure about that?
Try this version of the code
from scipy.integrate import quad
from scipy.constants import c, Planck, k, pi
import numpy as np
import matplotlib.pyplot as plt
R_est = 2.5 * (696.34e6)
def luminosity_integral(r, x):
T_est = 4000
termo1 = ((4 * pi * Planck * (x**4) ) / (c**2))
termo2 = ((Planck * x) / (k*T_est)) * (3*pi/2 * (r/R_est)**3)**0.25
termo3 = np.exp(-termo2)
return ((termo1 * r ) * termo3 / (1 - termo3))
freqs = np.logspace(6, 16)
y = np.zeros_like(freqs)
for i, nu in enumerate(freqs):
y[i] = quad(luminosity_integral, (6* R_est), (7e4 * R_est), args = (nu))[0]
plt.loglog(freqs, y)
plt.ylim([1e6, 1e25])
plt.show()
I am trying to compute the a bunch of first order derivates of a multi-variate function that may or may not be close-form. To provide you with more context, I am trying to compute 'Greeks' of options. Options price/value depend upon quite a few things: spot price, strike price, volatility and interest rates and so forth. One of the most commonly used Greek is called delta, which is the change in the price/value of an option with respect to one unit of change in the spot price of a stock. The option's price may not have a close-form/analytic form although here I use some close-form for the sake of simplicity. In reality, the price can be computed using Monte Carlo Simulation. The point is, I need a 'NumPy-friendly' way of computing these first order derivates of some function. This is where I believe a lot of machine learning/deep learning people may help me out. I took some introductory class of machine learning and know that there is a whole world of automatic differentiation, backward propagation and stuff. The library I use here is JAX and it seems to have some issue with 'numpy' as the error message goes like this:
The numpy.ndarray conversion method __array__() was called on the JAX Tracer object Traced<ConcreteArray(14793.626)>with<JVPTrace(level=2/0)>
with primal = DeviceArray(14793.626, dtype=float32)
tangent = Traced<ShapedArray(float32[]):JaxprTrace(level=1/0)>.
This error can occur when a JAX Tracer object is passed to a raw numpy function, or a method on a numpy.ndarray object. You might want to check that you are using `jnp` together with `import jax.numpy as jnp` rather than using `np` via `import numpy as np`. If this error arises on a line that involves array indexing, like `x[idx]`, it may be that the array being indexed `x` is a raw numpy.ndarray while the indices `idx` are a JAX Tracer instance; in that case, you can instead write `jax.device_put(x)[idx]`.
Note that I am working to utilize a 'pricer', a pricing function written by someone else and this pricing function is written in numpy and there is no way it can be written using other libraries. It'd be too much work. I have to 'apply' his pricing function written in numpy.
Btw, I modified the code I saw from some forum. In the original code, the function used is a five-variate function. All I did was simply add one variable called 'divyield', and it just wouldn't work! Thank you very much! I appreciate any help or pointer!
import jax.numpy as np
from jax.scipy.stats import norm
from jax import grad
import numpy as np
import scipy.stats as si
import sympy as sy
from sympy.stats import Normal, cdf
from sympy import init_printing
import jax.numpy as jnp
#import jnp
init_printing()
class EuropeanCall:
def __init__(self, inputs):
self.spot_price = inputs[0]
self.strike_price = inputs[1]
self.time_to_expiration = inputs[2]
self.risk_free_rate = inputs[3]
self.divyield=inputs[4]
self.volatility = inputs[5]
self.price = EuropeanCall.black_scholes_call_div(self.spot_price, self.strike_price, self.time_to_expiration,
self.risk_free_rate, self.divyield, self.volatility)
self.gradient_func = grad(EuropeanCall.black_scholes_call_div, (0, 1, 3, 4))
self.delta, self.vega, self.theta, self.rho = self.gradient_func(inputs[0], inputs[1], inputs[2], inputs[3],
inputs[4],inputs[5])
self.theta /= -365
self.vega /= 100
self.rho /= 100
#staticmethod
def black_scholes_call_div(S, K, T, r, q, sigma):
#S: spot price
#K: strike price
#T: time to maturity
#r: interest rate
#q: rate of continuous dividend paying asset
#sigma: volatility of underlying asset
#r=r+cds
d1 = (np.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = (np.log(S / K) + (r - q - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
call = (S * np.exp(-q * T) * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))
return call
class EuropeanPut:
def __init__(self, inputs):
self.spot_price = inputs[0]
self.strike_price = inputs[1]
self.time_to_expiration = inputs[2]
self.short_risk_free_rate = inputs[3]
self.divyield=inputs[4]
self.volatility = inputs[5]
self.price = EuropeanPut.black_scholes_put_div(self.spot_price, self.strike_price, self.time_to_expiration,
self.short_risk_free_rate,self.divyield,self.volatility)
self.gradient_func = grad(EuropeanPut.black_scholes_put_div, (0,1,3,4))
self.delta, self.vega, self.theta, self.rho = self.gradient_func(inputs[0], inputs[1], inputs[2], inputs[3],
inputs[4],inputs[5])
self.theta /= -365
self.vega /= 100
self.rho /= 100
#staticmethod
def black_scholes_put_div(S, K, T, r, q, sigma):
#S: spot price
#K: strike price
#T: time to maturity
#r: interest rate
#q: rate of continuous dividend paying asset
#sigma: volatility of underlying asset
#r=r+cds
d1 = (np.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = (np.log(S / K) + (r - q - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
put = (K * np.exp(-r * T) * si.norm.cdf(-d2, 0.0, 1.0) - S * np.exp(-q * T) * si.norm.cdf(-d1, 0.0, 1.0))
return put
#spot_price,vol, K,T,r
inputs = np.array([3109.62, .2102, 27/365,.017,0.02,0.25])
ec = EuropeanCall(inputs.astype('float'))
print(ec.delta, ec.vega, ec.theta, ec.rho)
The error message tells you what you need to do:
You might want to check that you are using jnp together with import jax.numpy as jnp rather than using np via import numpy as np
JAX cannot differentiate numpy functions, but it can differentiate jax.numpy functions. So replace np.log, np.sqrt, np.exp, etc. with jnp.log, jnp.sqrt, jnp.exp, etc., and similarly replace scipy calls with jax.scipy calls. Once all operations are implemented via JAX, you should be able to compute gradients with JAX.
If you're using a third-party module that is implemented in numpy that you cannot rewrite with JAX, then you will not be able to directly use JAX transforms, including auto-differentiation.
I have an implicit function to solve:
So I tried root finding functions from scipy.optimize:
- fsolve : RuntimeWarning: The iteration is not making good progress, as
measured by the improvement from the last ten iterations.
- excitingmixing : NoConvergence
-brent: RuntimeWarning: invalid value encountered in double_scalars (but
without a chance to set constraints)
I have to confess that I'm not sure about the correct solver. Could someone please help?
Minimal working example:
from scipy.optimize import fsolve, newton, brent, excitingmixing
import numpy as np
def func_zeta(zeta):
k= 1.2
Re = 5000.
d = 0.03
return (2.51 /Re/np.sqrt(zeta)+k/d/3.71) + 10**(0.5/ np.sqrt(zeta))
zeta = fsolve(func_zeta, 64/Re)
There were problems in your translation of the formula. Shouldn't it rather be the following return statement?
return 2.51 / (Re * np.sqrt(zeta)) + k / (d * 3.71) - 10 ** (-0.5 / np.sqrt(zeta))
But even then we get again a RuntimeWarning. Let's try again and substitute zeta:
from scipy.optimize import fsolve
import numpy as np
def zeta_in_disguise(x):
global k, d, Re
return x + 2 * np.log10(2.51 * x / Re + k / (d * 3.71))
k = 1.2
Re = 5000
d = 0.03
#x = 1 / np.sqrt(zeta)
x = fsolve(zeta_in_disguise, 0)
print(x)
#let's test, if x is really the solution to the equation
print(-2 * np.log10(2.51 * x / Re + k / d / 3.71))
Ah, now it is convergent and produces the following output
-2.06528864
And there we have the problem - there is no solution for your given parameters, at least not, when we only consider float numbers.