Can I skip the complex(imaginary results) in a numpy array? - python

Suppose I have a function like sqrt(x) and I am passing a list of numbers through it [-1,0,1].
This is going to give me an error saying that a negative argument is passed inside the square root function and the program is going to be halted after that without even checking for the 0 and 1 for which I would have gotten the real and "allowed" results in the first place.
Is there a way I can command python to ignore the values for which it would give errors and move on to the next part of the list?
Perhaps an algorithm like:
Start
x = [-1,0,1]
Pass this list through the function sqrt(x)
Ignore the values for which the function is going to the complex regime
Give the results ([-,0,1])
End
?
Thanks.

#matszwecja's answer assumes you can tell a priori which arguments give complex-valued answers. This is true for your sqrt example, but not in the general case. To filter after execution, a slight remix would be:
import numpy as np
arguments = [-1, 0, 1]
results = [x ** 0.5 for x in arguments] # stand in for your more general function
# use numpy for the filtering, for convenience
real_valued_args = np.array(arguments)[~np.iscomplex(results)]

import numpy as np
x = [-1, 0, 1]
print(np.sqrt(x))
numpys sqrt function is not throwing an error and returning only valid results.

Just do an explicit filter of your data:
import numpy as np
arr = np.array([-1,0,1])
filtered_arr = arr[arr >= 0]
print(np.sqrt(filtered_arr))

Related

How to create a loop to evaluate a conditional function

I am attempting to create a loop that will evaluate a function at discrete values. Normally this will be okay, however, this is proving to be difficult as my function is conditional (it has an adittional piecewise function which is dependent on the main variable.) This is an attempt I made below;
import math
import numpy as np
for i in np.arange(4000,8000,1000):
def f(λ,a,u,o1,o2):
o = o1 if (λ <= u) else o2
return a*math.exp((λ-u)^2/(-2*o^2))
print(f(i,1.056,5998,379,310))
I expected the code to evaluate the function at i=4000, then i=5000 etc. The output I recieve is as follows;
TypeError: ufunc 'bitwise_xor' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
I can't seem to find any specific examples for implementing a conditional function like this. Another attempt was made without a loop but I ran into value errors where I believe I was evaluating arrays as if they were one variable.
I wish to integrate and plot sums of the function later. Will I run into any issues with an approach involving a loop?
Python uses ** for exponentiation. ^ is bitwise xor.
Assuming your function is correct apart from the power operator **, a possible implementation with numpy would look like this
# import math # does not work well with numpy
import numpy as np
def f(l,a,u,o1,o2): # change 'λ' to 'l' (it's easier to type)
o = np.where(l <= u, o1, o2) # vectorize piecewise definition
return a*np.exp((l-u)**2/(-2*o**2)) # change '^' to '**' operator, use np.exp
x = np.arange(4000,8000,1000) # define value range
print(f(x,1.056,5998,379,310)) # call your function one time with entire range
Output
[9.74560013e-07 3.29586202e-02 1.05597802e+00 5.68878883e-03]
To reuse your function you can change it into a parameterized version
import numpy as np
def f(a,u,o1,o2):
return lambda x: a*np.exp((x-u)**2/(-2*np.where(x <= u, o1, o2)**2))
x = np.arange(4000,8000,1000)
f_p = f(1.056,5998,379,310) # parameterize your function
print(f_p(x)) # call the parameterized function with your value range
Output
[9.74560013e-07 3.29586202e-02 1.05597802e+00 5.68878883e-03]
import math
import numpy as np
def f(λ,a,u,o1,o2):
o = o1 if (λ <= u) else o2
return a*math.exp((λ-u)^2/(-2*o^2))
for i in np.arange(4000,8000,1000):
print(f(i,1.056,5998,379,310))
Try this code. This will work

Writing code to integrate 1D Fresnel Diffraction in Python

my task is to integrate the following equation for 1d Fresnel diffraction, in red in:
The point is that you are fourier transforming the aperture to a pattern on the screen, but for now just focussing on integrating the horizontal strip in 1d (ignoring the height for now). yprime is thus ignored. You also have fixed z and k, and j is an imaginary number. I have written the following code for it:
import math
import numpy as np
import cmath
k=5
z=5
x=0
j=cmath.sqrt(-1)
func=math.exp((j*k/2*z)(x-xp)*(x-xp))
def X(xp1,xp2,function,N):
h=(xp2-xp1)/N
y=0.0
xp=xp1
for x in np.arange(1, N/2 +1): #summing odd order y terms
y+=4*f(xp)
xp+=2*h
xp=xp1+2*h
for x in np.arange(0, N/2): #summing even order y terms
y+=2*f(x)
xp+=2*h
integral= (h/3)*(y+f(xp1)+f(xp2))
return integral
print(simpson(0,5,func,10))
however, it is saying that xp is not defined. but I clearly have defined xp in the function.
Does anyone have an idea what could be wrong?
Thanks
EDIT: here is a neater version of my code. But it's still asking me to define xp..
import math
import cmath
lamda=0.2
k=(2*math.pi)/lamda
z=0.1
def expfunc(x, xp):
func = math.exp(((1j)*k/2*z)(x-(xp))*(x-(xp)))
return(func)
def X(xp1,xp2,x,f,N):
h=(xp2-xp1)/N
y=0.0
xp=xp1
for i in np.arange(1, N/2 +1): #summing odd order y terms
y+=4*f(xp)
xp+=2*h
xp=xp1+2*h
for i in np.arange(0, N/2): #summing even order y terms
y+=2*f(xp)
xp+=2*h
integral= (h/3)*(y+f(xp1)+f(xp2))
return integral
print(X(0,1,x,expfunc,10))
You try to use the variable xp before you have defined it.
import math
import numpy as np
import cmath
k=5
z=5
x=0
j=cmath.sqrt(-1)
func=math.exp((j*k/2*z)(x-xp)*(x-xp)) #xp is not defined yet
You gave initial values for everything else except xp.
when you define func as you did
func=math.exp((j*k/2*z)(x-xp)*(x-xp))
you define a single value called func. What you probably want is something like that:
func = lambda x,xp : math.exp((j*k/2*z)(x-xp)*(x-xp))
and then change call of func to
y+=4*f(x, xp)
and
y+=2*f(x, xp)
I believe the issue is y+=4*f(xp) inside the first for loop of the function X.
At the very end you have print(X(0,1,x,expfunc,10)) where expfunc is acting as f in the bit of code y+=4*f(xp). The function expfunc takes two arguments, one of them defined as xp. Although the variable you pass in f is defined with the name xp, the function only sees that you have passed in the first argument x and not the argument xp.
Further, I do not see the variable x in print(X(0,1,x,expfunc,10)) defined anywhere.
Also, the second snipit of code is much different than the first. If the same questions apply then you should remove the first snipit altogether and/or rephrase your questions because from what I see in the second chuck the error you claim to be getting should not be raised.

Python Numba Polynomial Root Lower Error with Sympy

I have created a function which, given ranges of coefficients, constructs polynomials with such coefficients and outputs a list of all their roots. However, Numba doesn't like it. It's like this:
import math
import numpy as np
import itertools
from numba import jit
from sympy.solvers import solve
from sympy import Symbol
from sympy import Poly
#jit
def polyn(ranges=[[-20,20],[-20,20],[-20,20],[-20,20]],step=4):
l = []
x = Symbol('x')
rangl = [np.linspace(i[0],i[1],math.floor((i[1]-i[0])/step)) for i in ranges]
coeffl = iter(itertools.product(*rangl))
leng = 1
for i in rangl:
leng *= len(i)
for i in range(0, leng):
a = solve(Poly(list(next(coeffl)),x),x)
for j in a:
l.append(j)
return np.array(l)
When I try to run this, it outputs a cryptic:
AssertionError: Failed at object (object mode frontend)
which I do not understand... Can anyone help?
There are a number of things in your code which Numba can't cope with currently. The first is the list comprehension where you build rangl:
[np.linspace(i[0],i[1],math.floor((i[1]-i[0])/step)) for i in ranges]
You should replace this with a NumPy solution like:
rangl = np.empty((len(ranges), step))
for i in ranges:
rangl[i] = np.linspace(i[0],i[1],math.floor((i[1]-i[0])/step))
The second thing Numba can't cope with is itertools.product. You can replace that with NumPy and a for loop as well.
In general, try to reduce your code by commenting out the lower part of it until you get Numba to accept it, then work from the top down and see which parts it can't compile. Be methodical, go step by step, and try to stick to simple constructs like simple for loops and arrays.

Numpy and numdifftools multidimensional function

I'm using the package numddifftools to calculate the hessians of a multidimensional function (from R^n to R^n). While changing the code to use numpy arrays instead of lists, I discovered that doing so broke the code. Specifically:
import numpy as np
import numdifftools as nd
def function(x):
out = np.zeros(2)
out[0] = x[0] - x[1]**2/2.0
return float(out[0])
tempHessian = nd.Hessian(function, method='complex')
tempHessian([0.4,0.4])
Produces the error:
...\Continuum\Anaconda3\lib\site-packages\ipykernel_launcher.py:8: ComplexWarning: Casting complex values to real discards the imaginary part
and gives a zero hessian.
However, this one works fine:
import numpy as np
import numdifftools as nd
def function(x):
return x[0] - x[1]**2/2.0
tempHessian = nd.Hessian(function, method='complex')
tempHessian([0.4,0.4])
Any ideas what could be the problem? Thanks!
When out is created like this:
out = np.zeros(2)
it has type numpy.float64. You can't assign a complex value to such an array. Depending on which version of numpy that you are using, you'll get a warning or an error.
The complex step method for numerical differentiation requires that your function works with complex values. Forcing out to be numpy.float64 breaks that method. Converting the return value to floating point with float(out[0]) also breaks the method.
You can try something like this:
def function(x):
out = np.zeros(2, dtype=x.dtype)
out[0] = x[0] - x[1]**2/2.0
return out[0]
This creates out with the same data type as x. So if x is complex, the return value is also complex, as required by the complex step method.
(Of course, we don't know why you create out to have size 2, when only the first element is used. Presumably this is a simplification of the actual code that you are working with.)

Function to calculate and plot arctanx

I need to write a function that can write and solve the inverse of tan for values that I input as two arrays. Sometimes the array on the denominator contains zero so always a division by zero occurs. I don't know how to get rid of the error and make the answer return pi/2 instead.
def deviation(x):
if capture(x)==True:
for i in range(len(yvf)):
theta=sp.arctan(xvf/yvf) #xvf and yvf are two arrays
First of all: write xvf[i] and yvf[i] to access the single elements of the arrays one after the other.
Secondly discern if yvf[i] equals zero or not:
if yvf[i] == 0:
theta = math.pi/2.0
else:
theta = sp.arctan(xvf[i]/yvf[i])
If you import numpy, I suggest using arctan2 instead of arctan (see this doc). This function manages zero values in the 2nd argument.
If not, you can solve this problem with atan2 function of math library and zip built-in function :
import math
xvf = [0.,2.,2.]
yvf = [20.,0.,2.]
def arctan(xvf,yvf):
return [math.atan2(x,y) for x,y in zip(xvf,yvf)]
print arctan(xvf,yvf)

Categories