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
Related
I am trying to solve this simple simultaneous equations using scipy's fsolve function:
x + 2 = 10 &
x^2 = 64.
I am expecting 8 as the solution. However I'm getting an error saying "minpack.error: Result from function call is not a proper array of floats."
I am pretty new to python scientific library. Can someone please explain how to solve this error? Thanks!
from scipy.optimize import fsolve
def equations(p):
x = p
return (x-8, x**2 - 64)
x = fsolve(equations, 1)
print(x)
When you look at how fsolve is defined in the scipy module we see:
def fsolve(func, x0, args=(), fprime=None, full_output=0,
col_deriv=0, xtol=1.49012e-8, maxfev=0, band=None,
epsfcn=None, factor=100, diag=None):
"""
Find the roots of a function.
Return the roots of the (non-linear) equations defined by
``func(x) = 0`` given a starting estimate.
Parameters
----------
func : callable ``f(x, *args)``
A function that takes at least one (possibly vector) argument,
and returns a value of the same length.
'''
So your input value for p should consist of just as many elements as are returned by your function. Try for example:
from scipy.optimize import fsolve
import numpy as np
def equations(p):
x1 = p[0]
x2 = p[1]
return x1-8, x2**2 - 64
x = fsolve(equations, np.array([1, 2]))
print(x)
which gives 8, 8 as an answer.
I want to ask something that provably is extremly easy but I didn't find how to do it... The point is that I want to define some function in python in a symbolic way using sympy in order to make its derivative and then use this expresion numerically.
Here an example is showed:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
#How can I evaluate numerically this array "x" with the function deriv???
Do you know how to do it? Thanks!
You can use lambdify with the numpy backend:
import numpy as np
from sympy import *
z = Symbol('z')
function = z*exp(z**2)
deriv = diff(function, z)
x = np.arange(1, 3, 0.1) #interval of points
d = lambdify(z, deriv, "numpy")
d(x)
# array([ 8.15484549e+00, 1.14689175e+01, 1.63762998e+01,
# 2.37373255e+01, 3.49286892e+01, 5.21825471e+01,
# 7.91672020e+01, 1.21994639e+02, 1.90992239e+02,
# 3.03860954e+02, 4.91383350e+02, 8.07886132e+02,
# 1.35069268e+03, 2.29681687e+03, 3.97320108e+03,
# 6.99317313e+03, 1.25255647e+04, 2.28335915e+04,
# 4.23706166e+04, 8.00431723e+04])
So pretty much, I am aiming to achieve a function f(x)
My problem is that my function has an integral in it, and I only know how to construct definite integrals, so my question is how does one create an indefinite integral in a function (or there may be some other method I am currently unaware of)
My function is defined as :
(G is gravitational constant, although you can leave G out of your answer for simplicity, I'll add it in my code)
Here is the starting point, but I don't know how to do the integral portion
import numpy as np
def f(x):
rho = 5*(1/(1+((x**2)/(3**2))))
function_result = rho * 4 * np.pi * x**2
return function_result
Please let me know if I need to elaborate on something.
EDIT-----------------------------------------------------
I made some major progress, but I still have one little error.
Pretty much, I did this:
from sympy import *
x = Symbol('x')
rho = p0()*(1/(1+((x**2)/(rc()**2))))* 4 * np.pi * x**2
fooply = integrate(rho,x)
def f(rx):
function_result = fooply.subs({x:rx})
return function_result
Which works fine when I plug in one number for f; however, when I plug in an array (as I need to later), I get the error:
raise SympifyError(a)
sympy.core.sympify.SympifyError: SympifyError: [3, 3, 3, 3, 3]
(Here, I did print(f([3,3,3,3,3]))). Usually, the function returns an array of values. So if I did f([3,2]) it should return [f(3),f(2)]. Yet, for some reason, it doesn't for my function....
Thanks in advance
how about:
from sympy import *
x, p0, rc = symbols('x p0 rc', real=True, positive=True)
rho = p0*(1/(1+((x**2)/(rc))))* 4 * pi * x**2
fooply = integrate(rho,x)/x
rho, fooply
(4*pi*p0*x**2/(1 + x**2/rc),
4*pi*p0*rc*(-sqrt(rc)*atan(x/sqrt(rc)) + x)/x)
fooply = fooply.subs({p0: 2.0, rc: 3.0})
np_fooply = lambdify(x, fooply, 'numpy')
print(np_fooply(np.array([3,3,3,3,3])))
[ 29.81247362 29.81247362 29.81247362 29.81247362 29.81247362]
To plug in an array to a SymPy expression, you need to use lambdify to convert it to a NumPy function (f = lambdify(x, fooply)). Just using def and subs as you have done will not work.
Also, in general, when using symbolic computations, it's better to use sympy.pi instead of np.pi, as the former is symbolic and can simplify. It will automatically be converted to the numeric pi by lambdify.
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.
I am relatively new to Python and trying to use it to solve an integrator problem
x' = - L * x
Where L is the Laplacian Matrix, that is a matrix representation of a graph. This is part of my code:
def integrate_cons(x, t, l):
xdot = -l*x
return xdot;
t = np.linspace(0, 10, 101)
#laplacian is a 3x3 matrix
#initial_condition is a vector
solution = odeint(integrate_cons, initial_conditions, t, args=(laplacian,))
print solution
I'm having problems to pass a matrix like an argument in odeint. How can i solve?
import numpy as np
from scipy.integrate import odeint
def integrate_cons(x, t, l):
# unless you use np.matrix which I never do, you have to use np.dot
xdot = -np.dot(l,x)
return xdot;
t = np.linspace(0, 10, 101)
# just a random matrix
l = np.random.rand(3,3)
# initial conditions
x0 = np.array([1,1,1])
#laplacian is a 3x3 matrix
#initial_condition is a vector
solution = odeint(integrate_cons, x0, t, args=(l,))
print(solution)
Look at the scipy cookbook for examples.