Sympy Lambdify with array inputs - python

I am trying to give an array as input and expect an array as output for the following code.
from sympy import symbols
from sympy.utilities.lambdify import lambdify
import os
from sympy import *
import numpy as np
text=open('expr.txt','r')
expr=text.read()
x,param1,param2=symbols('x param1 param2')
params=np.array([param1,param2])
T=lambdify((x,params),expr,modules='numpy')
data=np.genfromtxt('datafile.csv',delimiter=',')
print T(data[0],[0.29,4.5])
text.close()
But get the following error.
TypeError: <lambda>() takes exactly 3 arguments (13 given)
How do i tell sympy that its a single array? Thanks in advance.

1. Solution:
Your problem is, that the function T expects a value, but you are handing out a list. Try this instead of print T(data[0],[0.29,4.5])to get a list of results:
print [T(val,[0.29,4.5]) for val in data[0]]
Or use a wrapper function:
def arrayT(array, params):
return [T(val, params) for val in array]
print arrayT(data[0], [0.29, 4.5])
2. Solution: You have to change your mathematical expression. Somehow sympy doesn't work with list of lists, so try this:
expr = "2*y/z*(x**(z-1)-x**(-1-z/2))"
T=lambdify((x,y,z),expr,'numpy')
print T(data[0], 0.29, 4.5)

Related

How to solve the 'mul objective has no attribute 'cos' '

How to solve the multi object problem?
import sympy as sym
from sympy import lambdify
x = sym.Symbol('x')
n = sym.Symbol('n')
f = sym.sin(n*x)
derivative_f = f.diff(x)
derivative_f = lambdify(x, derivative_f)
x = float(input('x:'))
print(derivative_f(x))
print(derivative_f)
If I input 2, the expected result should be 2*cos(2*x).
Your code contains a few misconceptions. One problem is an important general programming rule: try to use different variable names for variables with different meanings. So, x shouldn't be assigned a float, as it was a symbolic variable before. And derivative_f being a symbolic expression, shouldn't be assigned the result of lambdify.
Note that sympy's symbolic world doesn't mix well with the numeric world of non-sympy functions. lambdify forms a bridge between these worlds, from completely symbolic to completely numeric. E.g. the function created with lambdify doesn't have access to the symbolic n anymore.
The code lambdify(x, derivative_f) contains an error. derivative_f is a symbolic expression containing two symbolic variables (x and n), so it needs to be called as derivative_f_x_n = lambdify((x, n), derivative_f) (also giving the result a different name). Afterwards, you can use numeric expressions as derivative_f_x_n(7, 8), but you can't use symbolic parameters anymore.
For what you seem to be trying to do, lambdify isn't adequate. To get the derivative with x substituted, you call .subs(x, new_value) directly on the symbolic version of derivative_f:
import sympy as sym
from sympy import lambdify
x = sym.Symbol('x')
n = sym.Symbol('n')
f = sym.sin(n * x)
derivative_f_x = f.diff(x)
x_float = 2.0
print(derivative_f_x.subs(x, x_float))
Output: n*cos(2.0*n)
Also note that sympy strongly prefers to work with exact symbolic expressions, and using floats inevitably brings in approximations. Whenever possible, integers, sympy fractions (sym.S(1)/2) or symbolic expressions (sym.sqrt(5)) are recommended.
You call also use the derivative with respect to x and then substitute n:
print(f.diff(x).subs(n, 2))
Output: 2*cos(2*x)
To use that function later on in numeric calculations, after substitution you only have one symbolic variable left(x):
g = lambdify(x, f.diff(x).subs(n, 2))
You can type help(g) to see its generated source code:
Source code:
def _lambdifygenerated(x):
return (2*cos(2*x))
Then you can use g e.g. to create matplotlib plot. After lambdify nothing is symbolic anymore.
import matplotlib.pyplot as plt
import numpy as np
xs = np.linspace(0, 10)
plt.plot(xs, g(xs))
The other answer hit the key point, that you needed to account for the symbolic n when lambdifying.
Look at the help of your function:
In [2]: help(derivative_f)
Help on function _lambdifygenerated:
_lambdifygenerated(x)
Created with lambdify. Signature:
....
Source code:
def _lambdifygenerated(x):
return (n*cos(n*x))
It's a function of x, drawing n from the global environment, here a symbol.
The full error message when given an array argument:
In [5]: derivative_f(np.array([.1,.2,.3]))
AttributeError: 'Mul' object has no attribute 'cos'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<ipython-input-5-e04e9f3c0a8e>", line 1, in <module>
derivative_f(np.array([.1,.2,.3]))
File "<lambdifygenerated-1>", line 2, in _lambdifygenerated
return (n*cos(n*x))
TypeError: loop of ufunc does not support argument 0 of type Mul which has no callable cos method
See the return line in the traceback. That's the 'source code' in the help, and tells you what numpy is trying to execute.
test the inner expression of that line:
In [6]: n*np.array([.1,.2,.3])
Out[6]: array([0.1*n, 0.2*n, 0.3*n], dtype=object)
This is an object dtype array. Math on such an array delegates the calculation to each of the elements. Specifically it tries
(0.1*n).cos()
0.1*n is a sympy mul expression, hence the error. symbols often don't work in numpy expressions.
lambdify is a handy way of creating numpy functions from sympy expressions, but it needs to be used with care, and full awareness of what it does, and does not, do.

Vector definition through sympify method in Sympy

I use Sympy in my Python project, were the string definition of the expression converted to Sympy through sympify method. For example:
import sympy as sp
exp1 = sp.sympify('Add(Rational(1, 5), pi)')
While I am able to describe almost all functionality, I ran into the problem of Vector description to be understood by sympify method. Vector definition in normal way:
from sympy.vector import CoordSys3D
R = CoordSys3D('R')
v = 3*R.i + 4*R.j + 5*R.k
Next example (one of a variety) is failing:
exp2 = sp.sympify('Vector(Coord3D().i*3, Coord3D().j*4, Coord3D().k*5')
I would like to keep Vector format to support the curl, divergence and gradient functionality. Definition of 1-row matrix does not suit here for me. Documentation research did not give results.
I would be grateful for an example or suggestion of the right way for the sympy.vector definition for the sympify method.
If you pass in a locals dictionary, will that do what you want:
>>> from sympy.vector import *
>>> sympify('Vector(R.i*3, R.j*4, R.k*5)',
... locals=dict(R=CoordSys3D('R'), Vector=Vector))
Vector(3*R.i, 4*R.j, 5*R.k)
>>> type(_)
<class 'sympy.vector.vector.Vector'>

how to check that some input is of type sympy function?

I just started learning basic parsing in sympy, and having little trouble with this.
I want to make a proc(), which the caller will pass it a symbolic function, and the argument to the function, each as separate argument. i.e. instead of calling the proc as proc( y(x) ), I wanted to call it as proc(y,x), which I thought will be easier for me to check its arguments are what should be.
Next, inside the proc, wanted to first verify that the first argument type is indeed a sympy function and the second argument is a sympy symbol before doing any processing.
What is the correct way to check that the argument is a sympy function and nothing else? This is what I tried. Created one file:
================
def process(y,x):
if not isinstance(x, sympy.Symbol):
raise Exception(x + " should be a sympy symbol")
if not isinstance(y,sympy.UndefinedFunction): #this does not work
raise Exception(y + " should be a sympy function")
import sympy
x = sympy.symbols('x')
y = sympy.Function('y')
process(y,x)
======================
But there is no sympy.UndefinedFunction. When I type
type(y)
Out[18]: sympy.core.function.UndefinedFunction
But
isinstance(y,sympy.core.function.UndefinedFunction)
does not work either. May be there is a better way to do all the above. Basically I wanted to make sure the input to the proc is what it should be.
Using 3.7 (conda)
Replace sympy.UndefinedFunction with sympy.function.UndefinedFunction.
Also, x and y in Exception function should be of type string, otherwise you will get unsupported operand type(s) for +: error in both cases.
New code:
def process(y,x):
if not isinstance(x, sympy.symbol.Symbol):
raise Exception(str(x) + " should be a sympy symbol")
if not isinstance(y,sympy.function.UndefinedFunction):
raise Exception(str(y) + " should be a sympy function")
import sympy
x = sympy.symbols('x')
y = sympy.Function('y')
process(y,x)

round() function not working for databricks-Python

I am trying to use the round() function in databricks to round some float values to 2 digits. However, the databricks python is not working like normal python.
Please help me with the reasons and solutions if any.
lis = [-12.1334, 12.23433, 1.2343, -104.444]
lis2 = [round(val,2) for val in lis]
print(lis2)
TypeError: Invalid argument, not a string or column: -12.1334 of type <type 'float'>. For column literals, use 'lit', 'array', 'struct' or 'create_map' function.
Image Proof of Code
This is only reproducible when you import the spark round function from the function module in spark.sql
The spark round function requires a string or a column. Which explains the error.
You can either alias the import such as import pyspark.sql.functions as F instead of from pyspark.sql.functions import *
You can get the origin round method this way.
import builtins
round = getattr(builtins, "round")
And then you can execute
lis = [-12.1334, 12.23433, 1.2343, -104.444]
lis2 = [round(val, 2) for val in lis]
print(lis2)
Good day, The question is most likely with name-space conflict. I ran ran something like
from pyspark.sql.functions import *
Which contains function round. You can easily see which round is in usage by running help on it:
help(round)
Easy fix for this is to designate pyspark function to different name-space.
import pyspark.sql.functions as F
lis = [-12.1334, 12.23433, 1.2343, -104.444]
lis2 = [round(val,2) for val in lis]
print(lis2)
[-12.13, 12.23, 1.23, -104.44]
Try this:
lis = [-12.1334, 12.23433, 1.2343, -104.444]
list_em = []
for row in lis:
list_em.append(round(row,2))
print(list_em)
[-12.13, 12.23, 1.23, -104.44]
I believe this is the source code for the function you are applying:
def round(col, scale=0):
"""
Round the given value to `scale` decimal places using HALF_UP rounding mode if `scale` >= 0
or at integral part when `scale` < 0.
>>> spark.createDataFrame([(2.5,)], ['a']).select(round('a', 0).alias('r')).collect()
[Row(r=3.0)]
"""
sc = SparkContext._active_spark_context
return Column(sc._jvm.functions.round(_to_java_column(col), scale))
Clearly it says to pass in a column, not a decimal number. Did you import *? That could have overridden the builtin function.

scipy -- how to convert a function result to array

Hello i have the function Walk1d which then i want to calculate the cumsum.
I use Walk1d=lambda n: sc.cumsum(steps(n)) .The result is an array but when i am trying Walk1d.cumsum() it doesn't work because type(Walk1d) is a function.
If i try sc.array(Walk1d).cumsum() it gives me : at 0x3798488>
How can i handle this?
import matplotlib.pyplot as plt
import scipy as sc
steps=lambda m: 2*sc.random.random_integers(0,1,size=m)-1
Walk1d=lambda n: sc.cumsum(steps(n))
print(sc.array(Walk1d).cumsum())
Thanks!
Walk1d is a function taking an argument. You have to call the function and pass in an argument to get a result, for example
print(Walk1d(10).cumsum())
The function Walk1d needs to be called with a parameter n:
print(sc.array(Walk1d(10)).cumsum())

Categories