import numpy
import matplotlib.pyplot as plt
from scipy import integrate
def f(x,y):
return x*y + x**2
def integral(x,y):
I = integrate.quad(f, 0, x, args=(y,))[0]
return I
def gau(x,y):
return (1+x)*integral(x,y)
xlist = numpy.linspace(-3.0, 3.0, 100)
ylist = numpy.linspace(-3.0, 3.0, 100)
X, Y = numpy.meshgrid(xlist, ylist)
Z = gau(2, Y)
print(Z)
I keep on getting the error message "Supplied function does not return a valid float." , I think the problem is that I try to pass an array to the quad function. I thought about evaluating the integral for every entry of the array with something like that:
yi=numpy.linspace(-3.0,3.0,100)
for i, item in enumerate(yi):
return integral[i]=integrate.quad(f,0,x,args=(yi,))[0]
It doesn't work but is it the right way? Any other/better suggestions?
You could use a universal function (see https://docs.scipy.org/doc/numpy/reference/ufuncs.html) which operates on arrays element-by-element. You can create these universal functions from any function using the frompyfunc function (https://docs.scipy.org/doc/numpy/reference/generated/numpy.frompyfunc.html):
ugau = numpy.frompyfunc(gau,2,1)
Z=ugau(X,Y)
It if your f() that does not provide a valid float when passed an array, not the scipy.integral itself;
why do you pass an array to your f() ?
You can use quadpy (one of my projects). quadpy is fully vectorized with respect to the dimensionality of the function range and the domains, so you can plug in a function that returns a vector and integrate that function over many intervals at once. You just have to make sure that the input function deals with vectorized input correctly. In your case, that would be
import numpy
import quadpy
def f(x, y):
return numpy.multiply.outer(y, x) + numpy.multiply.outer(numpy.ones_like(y), x ** 2)
def integral(x, y):
scheme = quadpy.line_segment.gauss_legendre(5)
intervals = numpy.array([numpy.zeros_like(x), x])
out = scheme.integrate(lambda t: f(t, y), intervals)
return out
def gau(x, y):
return (1 + x) * integral(x, y)
xlist = numpy.linspace(-3.0, 3.0, 100)
ylist = numpy.linspace(-3.0, 3.0, 100)
Z = gau(2, ylist)
print(Z)
You also insert xlist instead of 2 here to compute it all at once.
Related
I am trying to build a few simple operations such as a derivative and integral function to operate on lambda functions because sympy and scipy were struggling to integrate some things that I was passing to them.
The derivative function does not give me any issues and looks to return the derivative of the input function when plotted, but the integral function does not return the same, and does not plot the correct integral of the input.
import matplotlib.pyplot as plt
import numpy as np
from phys_func import func
sr = [-10,10]
x = np.linspace(sr[0],sr[1], 100)
F = lambda x: x**2
f = func.I(F,x)
plt.plot(x,F(x), label = 'F(x)')
plt.plot(x,f(x), label = 'f(x)')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
The integration function that does not work:
def I(F,x):
dx = (x[len(x)-1] - x[0])/len(x)
return lambda x : 0.5*( F(x+dx) + F(x) )*dx
The derivative function that works:
def d(f,x):
dx = (x[len(x)-1]-x[0])/len(x)
return lambda x: (f(x+dx)-f(x))/dx
Can anyone lend me a hand please?
You cannot find the anti derivative of a function numerically with out knowing the value of the anti derivative at a single point. Suppose if you fix the value of the antiderivative function value at x =a to be 0 (and given function is continuous from [a,x]) , then we can use definite integrals. For this function, let us take a=0 (i.e 0 is a root of anti derivative function), so you can do a definite integral from [0,x]. Also, your integration function is wrong. You need to sum all the 0.5*( F(x+dx) + F(x) )*dx elements from 0 to x to get the definite integral.
You can modify I(f,x) as follows
def I(F1): # N is number of intervals
return lambda x, N: np.sum( 0.5*( F1(np.linspace(0,x,num=N)+ (x)/N ) + F1(np.linspace(0,x,num=N)))*(x)/N)
In [1]: import numpy as np
In [2]: def I(F1): # N is number of intervals
...: return lambda x, N: np.sum( 0.5*( F1(np.linspace(0,x,num=N)+ (x)/N
...: ) + F1(np.linspace(0,x,num=N)))*(x)/N)
...:
In [3]: F = lambda x: x**2
In [4]: x_ran = np.linspace(-10,10, 100)
In [5]: y = I(F)
In [6]: y_ran = []
In [7]: for i in x_ran:
...: y_ran.append(y(i,100))
In [8]: plt.plot(x_ran,y_ran)
In [9]: plt.show()
I am trying to find an array of integrate function but i have some problem with shapes and dimensions. I found coefficient k and then i found Energy for the interval x = (0,a), where a = 1 and n = (-Nmax, Nmax). I was also trying to vectorize them. But every time it gives me new errors. I'm not sure how to fix this, because i need this integrate function to call to another function to plot the graph.
def k_n(n):
k = fsolve(lambda n : np.tan(n*a/2.) - np.tanh(n*a/2.),n)
return(k)
def E(n):
return(np.piecewise(n,[n<0.,n>=0.],
[lambda n: -k_n(n)**2 ,
lambda n: k_n(n)**2 ]))
def integrand1(x,n):
return(np.sin(k_n(n)*x)**2)
def integrand2(x,n):
return((np.sin(k_n(n)*a/2.))**2*(np.sinh(k_n(n)*(a-x)))**2/2*
np.exp(-a*k_n(n))*(np.sinh(k_n(n)*a/2.))**2)
def integrate(n):
integrand = spi.integrate.quad(integrand1,0,a/2,args=(n))+spi.integrate.quad(integrand2,a/2,a,args=(n))
one = np.true_divide(1, integrand )
return(one)
maybe the problem is with n_r and x_r
n_r = np.arange(-Nmax, Nmax,1)
x_r = np.arange(0,a,.1)
print(k_n(n_r))
print(E(n_r))
print(integrate(n_r))`
TypeError: only size-1 arrays can be converted to Python scalars.in _quad
return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit
You cannot send an array to your function for integration. The quad function expects to have only one output from the function (like you would expect from a mathematical function). But you can iterate over the n_r array:
n_r = np.arange(-Nmax, Nmax,1)
x_r = np.arange(0,a,.1)
print(k_n(n_r))
print(E(n_r))
print(np.array([integrate(n) for n in n_r]))
The result is a two-dimentional numpy array.
You can use
np.vectorize()
to create a vectorized version of the integral function.
from scipy.integrate import quad
def integrand(t, n, x):
return np.exp(-x*t) / t**n
def expint(n, x):
return quad(integrand, 1, np.inf, args=(n, x))[0]
vec_expint = np.vectorize(expint)
an example would be
>>>vec_expint(3, np.arange(1.0, 4.0, 0.5))
array([ 0.1097, 0.0567, 0.0301, 0.0163, 0.0089, 0.0049])
In case you are wondering, this example is given here
I need help to compute derivative and integral of function using finite difference method and Numpy without using loops.
The whole task: Tabulate Gauss function f(x) = (1./(sqrt(2.*pi)*s))*e**(-0.5*((x-m)/s)**2) on the interval [-10,10] for m = 0 and s=[0.5,5]. Compute derivative and integral of the function using finite difference method without using loops. Create plots of the function and its derivative. Use Numpy and Matplotlib.
Here's the beginning of the programm:
def f(x,s,m):
return (1./(sqrt(2.*pi)*s))*e**(-0.5*((x-m)/s)**2)
def main():
m = 0
s = np.linspace(0.5,5,3)
x = np.linspace(-10,10,20)
for i in range(3):
print('s = ', s[i])
for j in range(20):
f(x[j],s[i],m)
print('x = ',x[j],', y = ',f(x[j],s[i],m))
By using the numpy arrays you can apply that operation directly with algebraic notation:
result = (1./(np.sqrt(2.*np.pi)*s))*np.exp(-0.5*((x-m)/s)**2)
The simplest way (without using SciPy) seems to me to directly sum for the integral and central difference method for the derivative:
import numpy as np
import pylab
def gaussian(x, s, m):
return 1./(np.sqrt(2.*np.pi)*s) * np.exp(-0.5*((x-m)/s)**2)
m = 0
s = np.linspace(0.5,5,3)
x, dx = np.linspace(-10,10,1000, retstep=True)
x = x[:,np.newaxis]
y = gaussian(x,s,m)
h = 1.e-6
dydx = (gaussian(x+h, s, m) - gaussian(x-h, s, m))/2/h
int_y = np.sum(gaussian(x, s, m), axis=0) * dx
print(int_y)
pylab.plot(x, y)
pylab.plot(x, dydx)
pylab.show()
I want to create a function of a symbolic matrix in sympy and then lambdify it for evaluation in numpy. Let's try the simple function that returns exactly what I feed it f(x) = x, but eventually Id like to do something like take the trace of the matrix, or something fancier.
It's fine when x is a sympy.Symbol:
import sympy as sy
from sympy import Matrix, MatrixSymbol
x = sy.Symbol('x')
f = sy.lambdify(x, x, 'numpy')
f(Matrix((3,))) # returns Matrix([[3]])
But not when x is a sympy.MatrixSymbol:
import sympy as sy
from sympy import Matrix, MatrixSymbol
x = sy.MatrixSymbol('x', 2, 2)
f = sy.lambdify(x, x, 'numpy')
f(Matrix((3,))) # should return Matrix((3,)), right?
It tells me:
lambda() takes no arguments (1 given)
Thanks for any ideas or guidance!
Here's a cludge hack. mySymbol takes a string (keep it short), and n and m are the desired matrix dimensions.
def makeMatrix(mySymbol,n,m): #makes a lambdafiable matrix
myMatrix = zeros(n,m)
for i in numpy.arange(n):
for j in numpy.arange(m):
myStr = mySymbol+"_"+str(i)+"_"+str(j)
myMatrix[i,j]=sympify(myStr)
return myMatrix
I woul like to solve an n-dimensional optimisation problem using iminuit.
So my approach is the following.
I am trying to figure out how to extend this:
def f(x,y,z):
return (x-1.)**2 + (y-2*x)**2 + (z-3.*x)**2 -1.
to a variable "x" that is a numpy.array.
I would like to do something like this:
x = [1,2,3,4,5]
y = [2,4,6,8,10]# y=2x
class StraightLineChi2:
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self,m,c): #lets try to find slope and intercept
chi2 = sum((y - m*x+c)**2 for x,y in zip(self.x,self.y))
return chi2
but in my case x is my unknown, and it is an array. Like in many optimization/minimization problems, the function is a f=f(x1,...,xn) where n can be big. x1,...,xn are the unknowns of the problem.
(These examples are taken from here)
Something similar is achieved "hacking" pyminuit2, like described here
For your example I recommend you using iminuit and probfit. Having an argument as a list of parameter is not exactly what you want to do since you will get confused which parameter is what very soon.
Here is an example taken straight from probfit tutorial. Also see the documentation
import iminuit
import probfit
x = np.linspace(0, 10, 20)
y = 3 * x + 15 + np.random.randn(len(x))
err = np.ones(len(x))
def line(x, m, c): # define it to be parabolic or whatever you like
return m * x + c
chi2 = probfit.Chi2Regression(line, x, y, err)
minuit = iminuit.Minuit(chi2)
minuit.migrad();
print(minuit.values) #{'c': 16.137947520534624, 'm': 2.8862774144823855}