Python – Sympy – Solving equations numerically for multiple parameters in a grid

Question:

A given equation depends on an unknown variable (y) and a set of parameters. I would like to numerically solve for y, given each element of a grid with values of the parameters.

A simplified example of my attempted solution is as follows (y is the unknown variable and x is the parameter):

import numpy as np
import sympy as sp
x,y=sp.symbols('x y')
xgrid=np.arange(1,6)
f = sp.lambdify(x,sp.nsolve(x**2+y,y,2),"numpy")
print(f(xgrid))

However, I am getting the following error:

expected a one-dimensional and numerical function.

I was expecting to receive a vector with y=-x**2 for every value x in xgrid.

Please notice that the actual function of interest is not y=-x**2 as in the example, but a non-linear function that is implicit in both x in y.

Am I forced to do a loop over each value in the grid, or can I still use lambdify somehow? Thanks in advance!

Asked By: CarlosH

||

Answers:

When this line f = sp.lambdify(x, sp.nsolve(x**2+y,y,2),"numpy") is executing, first python executes sp.nsolve(x**2+y, y, 2). It is the issue on your code, SymPy has one equation to resolve with 2 unknowns.

Answered By: glegoux

The purpose of sympy.lambdify is to transform symbolic expressions into numerical ones. It makes no sense “lambdyfing” sympy.nsolve as the latter is (by default) a numerical function. If you need to define a “wrapper” function for sympy.nsolve you should do so by using the standard python approach.

def f(x):
    y = sp.symbols('y')
    return float(sp.nsolve(x**2+y,y,2))

Now calling f(xgrid), where xfrid is an ndarray makes no sense as the function accepts scalar arguments. You need to write a loop. If you are feeling lazy, you could instead use the convenient np.vectorize function, which makes a function evaluate for ndarrays even when it is defined only for scalar arguments. However, note that this approach is essentially a shorthand for a loop, i.e., it performs the exact same computations as if you had explicitly written a loop.

f = np.vectorize(f)
f(xgrid)

array([ -1., -4., -9., -16., -25.])

Answered By: Stelios