Integrating over an interpolate function (interp1d) in python - python

I am trying to do double integration over an interpolated function, in which r = r(x,y).
from scipy import interpolate
import scipy as sp
r = [0, 1, 2]
z = [0, 1, 2]
def cartesian(x, y, f):
r = sp.sqrt(x**2 + y**2)
return f(r)
interp = interpolate.interp1d(r, z)
print(cart(1,1,interp))
a = sp.integrate.dblquad(cart, 0, 1, lambda x: 0, lambda x: 1, args=(interp))
print(a)
Executing the Cartesian function once produces the correct answer. However the integral gives the the following error:
TypeError: integrate() argument after * must be an iterable, not interp1d
I don't understand why my function isn't iterable and do not know how to convert it into an iterable form. Many thanks for any help.

args is supposed to be a sequence of arguments, so:
sp.integrate.dblquad(cart, 0, 1, lambda x: 0, lambda x: 1, args=(interp,))
The comma after interp is critical: in Python, (x) is just x, but (x,) is a tuple (i.e. a sequence).

Related

how to fix "only length-1 arrays can be converted to Python scalars" when getting integral with an array argument

I am using quad from scipy.integrate to get an integral in a limited range from an object. suppose the target object is in the blow:
∫expm(A*X).expm(B*X)dx
which both A and B are numpy matrix.
To solve this I have used blow code:
from scipy.integrate import quad
from scipy.linalg import expm
import numpy as np
def integrand(X, A, B):
return np.dot(expm(A*X),expm(B*X))
A = np.array([[1, 2], [3, 4]])
B = np.array([[1, 2], [3, 4]])
I= quad(integrand, 0, 1, args=(A,B))
But for the result I get this error:
TypeError: only length-1 arrays can be converted to Python scalars
I know that The error "only length-1 arrays can be converted to Python scalars" is raised when the function expects a single value but you pass an array instead. but my problem is based on array. so how can I fix it.
As pointed in the comments, quad expects a scalar function. You can always pass the function to a scalar by adding the index as an output:
def integrand(X, A, B, ix=None):
""" pass ix=None to return the matrix, ix = 0,1,2,3 to return an element"""
output = np.dot(expm(A*X),expm(B*X))
if ix is None:
return output
i, j = ix//2, ix%2
return output[i,j]
I= np.array([quad(integrand, 0, 1, args=(A,B, i))[0]
for i in range(4)]).reshape(2,2)
I
>>array([[1031.61668602, 1502.47836021],
[2253.71754031, 3285.33422634]])
Note that this is very inefficient since you are calculating the integral 4 times, as long as this doesn't bother you.
Alternatively, use trapz:
x_i = np.linspace(0,1,60)
np.trapz([integrand(x, A, B) for x in x_i], x=x_i, axis=0)
>>array([[1034.46472361, 1506.62915374],
[2259.94373062, 3294.40845422]])
quadpy does vectorized computation. The fact that expm only works on square matrices (and not on lists of square matrices) requires a bit of juggling with the matrix shapes, though.
from quadpy import quad
import numpy as np
from scipy.linalg import expm
A = np.array([[1, 2], [3, 4]])
B = np.array([[1, 2], [3, 4]])
def integrand(X):
expAX = np.array([expm(A * x) for x in X])
expAX = np.moveaxis(expAX, 0, -1)
#
expBX = np.array([expm(B * x) for x in X])
expBX = np.moveaxis(expBX, 0, -1)
return np.einsum("ij...,jk...->ik...", expAX, expBX)
val, err = quad(integrand, 0, 1)
print(val)
[[1031.61668602 1502.47836021]
[2253.71754031 3285.33422633]]

Failed to show calculation steps with sympy and markdown

Question
I want to show the steps of calculation (for example, in text book) in markdown file which is created by a python code. here is what I need in original python code
from sympy import *
angle = 60 # this will be changed to created different markdown files
theta = symbols('ss')
x = symbols('xx')
a = Matrix([[cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]])
b = Matrix([[x, 0, 0], [0, x, 1], [0, 0, 0]])
print(
'$$',
latex(a), latex(b), '=', # step 1
latex(a).replace('ss', latex(rad(angle))), latex(b).replace('xx', '2'), '=', # step 2
latex(a.subs('ss', rad(60))), latex(b.subs('xx', '2')), '=', # step 3
latex((a*b).subs({'ss': rad(60), 'xx':2}).evalf(2)), # step 4
'$$'
)
you may find that step 1 lists the common matrix, step 2 substitutes the element of matrix by given value, step 3 calculates/simplifies the matrix and step 4 evaluates the matrix elements to float form.
There are too many calls of latex which make the code too long and hard to read.
First try
I write
from sympy import *
class T_Rotate(object):
def __init__(self, theta):
self.eq = Matrix([[cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]])
self.str = latex(self.eq)
def __mul__(self, mat):
return self.eq * mat
def __rmul__(self, mat):
return mat * self.eq
a = T_Rotate(60)
b = Matrix([[1, 0, 0], [0, 1, 1], [0, 0, 0]])
print('$$a*b = %s * %s = %s$$' % (a.str, latex(b), latex(a*b)))
print('$$b * a = %s * %s = %s$$' % (latex(b), a.str, latex(b*a)))
but above a * b is a wrong answer which is a 3*3 matrix but whose elements are all 3*3 matrix!
so, what is the problem?
Further thought
In case the above be fixed, there are still call of latex function. Any hints to wrap sympy expression so that the python code can be more terse?
thanks
Now I wrote https://github.com/retsyo/expand_expression to answer the post partly. But I am also still seeking for a more common method without supplying every functions by the user
I released it for it can help others. Here is a example:
If you have defined a function, then you can use it like
T1 = T_Rotate('pi/6 + pi/2', useRad=True)
fOut.write(latexExpression('T1'))
Is it easy? I think so.

Combination of Map and Integration

This is the equation that I'm trying to plot, but have not been successful for hours. XA is variable between 0 to 1. I'd like to plot it while I'm varying eA and n constants. I'm still learning Python and this is being too complicated for me. Any help will be very appreciable.
XA = np.linspace(1e-2, 1-1e-2, 20)
from scipy.integrate import quad
def integrand(XA):
return ((1+eA*XA)/(1-XA))**n
p = lambda XA: quad(integrand, 1e-2, XA)[0]
xs = 1-XA
def func(n, eA):
return (XA*((1+eA*XA)/(1-XA))**n)/(p)
n = [1, 1, 2, 2]
eA = [1, 2, 1, 2]
ys = list(map(func, alps, e))
plt.plot(xs, ys)
plt.show()
You need to evaluate the functions in order to use them in further calculations. Also make sure to supply the needed arguments to the functions.
Here would be an example:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
bracket = lambda eA,XA,n: ((1+eA*XA)/(1-XA))**n
p = lambda eA,XA,n: quad(lambda x: bracket(eA,x,n), 1e-2, XA)[0]
func = lambda eA,XA,n: XA*bracket(eA,XA,n)/p(eA,XA,n)
ns = [1, 1, 2, 2]
eAs = [1, 2, 1, 2]
XAs = np.linspace(3e-2, 1-1e-2, 50)
for e,n in zip(eAs,ns):
ys = list(map(lambda x: func(e,x,n), XAs))
plt.plot(XAs, ys, label="n={}, $e_A$={}".format(n,e))
plt.xlabel("$X_A$")
plt.legend()
plt.show()

python (scipy): How to find multiple roots of an equation by passing in the jacobian as well

Problem Statement:
Consider the following code.
import numpy as np
from scipy import optimize
def func(x, y):
out = 2 * np.arccos(1-x) - np.sin(2 * np.arccos(1- x)) - y
return out
def jac(x,y):
out = 4 * np.sin(np.arccos(1 - x))
return out
initial_guesses = np.array([0.25, 0.75, 1, 1.25, 1.5])
args = (1, 2, 3, 4, 5,)
multiple_roots = optimize.root(func, x0 = initial_guesses, method='hybr',
args=(args,))
Everything works fine.
Passing in the Jacobian
But I also want to pass in the jacobian I calculated above as well. When I do:
initial_guesses = [0.25, 0.75, 1, 1.25, 1.5]
args = (1, 2, 3, 4, 5,)
multiple_sol_with_jac = optimize.root(func, x0 = initial_guesses, method='hybr',
args=(args,), jac=jac)
Error:
It gives me the following error
TypeError: fsolve: there is a mismatch between the input and output shape of the 'fprime' argument 'jac'.Shape should be (5, 5) but it is (5,)
A similar question was asked here. But it does not address passing in the jacobian when using scipy.optimize.root to find multiple roots.
Attempt:
Obviously we want to account now for the fact that we have a list of points at which we seek roots. So the jacobian needs to be appropriately modified to output a matrix rather than a scaler. I tried doing jac = [jac] * 5 but it doesn't work.
Question:
How do I pass in the jacobian appropriately in this case?

Inverse function of numpy.polyval()

I was wondering is there a convenient inverse function of np.polyval(), where I give the y value and it solves for x?
I know one way I could do this is:
import numpy as np
# Set up the question
p = np.array([1, 1, -10])
y = 100
# Solve
p_temp = p
p_temp[-1] -= y
x = np.roots(p_temp)
However my guess is most would agree on that this code has low readability. Any suggestions?
How about something like this?
In [19]: p = np.poly1d([1, 1, -10]) # Use a poly1d to represent the polynomial.
In [20]: y = 100
In [21]: (p - y).roots
Out[21]: array([-11., 10.])
The poly1d object implements the arithmetic operations to return a new poly1d object, so p - y is a new poly1d:
In [22]: p - y
Out[22]: poly1d([ 1, 1, -110])
The roots attribute of a poly1d returns what you would expect.

Categories