Python (SymPy, SciPy), create symbol lambda from string - python

I've struggling to take text inputs of an equation and evaluate it as a definite integral. I need a callable function to pass to scipy.integrate.
eq = "x**2"
func = lambda x: eq
func(2)
# outputs:
# x**2
# but if I:
func = lambda x: x**2
func(2)
# outputs:
# 4

Not sure, but maybe you are looking for
eq = "x**2"
func = eval("lambda x: " + eq)
Note that using eval() is dangerous if eq is from an untrusted source (e.g. user input).

You need to use eval to run eq as code and not treat it as a string.
eq = "x**2"
func = lambda x: eval(eq)
func(2)
# outputs:
# 4

sympify may be what you are looking for. It converts a string expression into an sympy object.
For example:
import sympy as sp
f=sp.sympify('x**2+sin(y)')
And you can use autowrap to convert a sympy object into a callable function.

Try asteval or numexpr for possibly safer alternatives to eval() and Sympy.sympify().evalf().

I continually got a syntax error for the following and relentlessly was trying to find out why:
E="2x+1"
F=lambda x: (x, eval(E)) # to get an xy coordinate
But the issue worked as expected when I changed E to:
E="2*x+1"
Rookie mistake. :)

Related

Convert String to Algebraic Expression in Python

I have a simple differentiation function
def differentiate(func, num) -> float:
x = num
h = 0.000000001
der = (func(x+h)-func(x))/h
return round(der,4)
print(differentiate(lambda x: x+5,10))
Which gives the expected output of 1.0 But I want to make the func argument such that it only needs the expression to be in the form of a string. For example:
print(differentiate('x+5', 10))
Is this possible to do? Preferably without the help of modules.
It depends whether x is always your variable. If it is the case, then you can use the eval function of python which parses your string and evaluate it as a python expression:
def differentiate(func_x, num) -> float:
x = num
h = 0.000000001
func = lambda x: eval(func_x)
der = (func(x+h)-func(x))/h
return round(der,4)
print(differentiate('x+5', 10))
>>> 1.0
Edit:
As Serge Ballesta pointed out below, the eval function may have security issues as it allows uncontrolled execution at run time, i.e. it will execute any piece of code given in input, so only use it if you can trust the input of your function.

How to save a function as string in Python?

Given the following math function in form of a Python function:
import math
def f(x):
a = x - math.log(x)
b = x + math.log(x)
return a / x + b / math.log(x)
Is there any way that I can convert this function into a string like
expr = '(x - math.log(x)) / x + (x + math.log(x)) / math.log(x)'
so that when I want to call the function, I can simply use it by
func = lambda x: eval(expr)
print(func(3))
# 4.364513583657809
Note that I want to keep a and b in the original function. In reality, I have a lot more intermediate variables. Also, I am aware sympy could do similar tasks, but I would like to know if it is possible to convert the function to string, as it would be much more efficient to store.
Any suggestions?
Your function is already a string the moment you write it to a file!
If the function is valid Python, you can then just import it
from myfile import expr
print(expr(3)) # 4.364513583657809
WARNING Do not ever do this
If you want some incredibly evil logic for some reason, you can save your function directly with inspect.getsource(f) and then do something like this
>>> fn_body = """def f(x):
... a = x - math.log(x)
... b = x + math.log(x)
... return a / x + b / math.log(x)
... """
>>> eval(f'lambda {fn_body.split("(")[1].split(")")[0]}, _={exec(fn_body)}: {fn_body.split(" ", 1)[-1].split(")")[0]})')(3)
4.364513583657809
This works by finding the parts needed to call the function, evaluating the source as one of the args (to smuggle it into your namespace), and then building an anonymous function to call it
Further Caveats
not remotely maintainable
extremely fragile
will clobber or conflict with an existing function with the same name depending on use
you will still need to import math or whatever other libraries
won't work with default args without more pain
calling eval() first (before creating the lambda) will allow you to use inspect to get the signature (.signature()) and you can combine it with re and/or ast for a much robust parser, but a 1-liner seemed more exciting
manages to use both eval() and exec() for an extra helping of evil
You're probably looking for a symbolic equation solver!
Sympy's lambdify feature can do this for you!
>>> fn = sympy.lambdify("x", '(x - log(x)) / x + (x + log(x)) / log(x)')
>>> fn(x=3)
4.364513583657809
Caution: this also uses eval internally as #Joshua Voskamp warns about in a comment

sympy parser doesn't identify expm1 as a symbolic function

The function expm1 is not parsed properly in the following example:
from sympy.parsing.sympy_parser import parse_expr
print parse_expr('expm1(x)').diff('x')
gives
Derivative(expm1(x), x)
How can I get sympy identifying expm1 as symbolic function, so that I get the same result as
print parse_expr('exp(x) - 1').diff('x')
which gives exp(x)?
Since there is no built-in expm1 in SymPy, the parser does not know anything about this notation. The parameter local_dict of parse_expr can be used to explain the meaning of unfamiliar functions and symbols to SymPy.
expm1 = lambda x: exp(x)-1
parse_expr('expm1(x)', local_dict={"expm1": expm1})
This returns exp(x) - 1.
For expm1 to remain a single function with known derivative, rather than exp(x)-1, define it as a SymPy function (see tutorial for more such examples).
class expm1(Function):
def fdiff(self, argindex=1):
return exp(self.args[0])
A confirmation that this works:
e = parse_expr('expm1(x)', local_dict={"expm1": expm1})
print(e) # expm1(x)
print(e.diff(x)) # exp(x)
f = lambdify(x, e)
print(f(1)) # 1.718281828459045
print(f(1e-20)) # 1e-20, unlike exp(x)-1 which would evaluate to 0

python 3.4 lambda and revrse her how

I have question about python 3.4.
let's say I do:
inches_to_meters =lambda x: x*0.0254
inches_to_feets =lambda x: x*(1/12)
miles_to_feets =lambda x: x*5280
I want to know how to calculate the opposite function, only with lambda how can I do it?
For example:
feets_to_inches = opposite(inches_to_feets)
or for more example I want composition with lambda only:
miles_to_inches = composition(feets_to_inches, miles_to_feets)
tnx for the help
The task is specifically limited to converting distances using the specified lambdas as the base and using an opposite and composition lambdas for the rest.
Since the conversion of these units is rather simple, you can get the conversion factor by dividing by 1 first. Basically:
opposite = lambda f: lambda x: x/f(1)
As Willem Van Onsem says, you cannot automatically define the inverse of a function. You can, however, compute the appropriate conversion factor and pass that to a converter-making function.
def make_converter(factor):
def _(x):
return x * factor
return _
inches_in_feet = 12
feet_to_inches = make_converter(inches_in_feet)
inches_to_feet = make_converter(1/inches_in_feet)
Composition, however, is trivial (assuming the output of the first function
is the expected input of the second):
def composition(f, g):
return lambda x: f(g(x))

Force function argument to be a string

So, my code is like this:
def func(s,x):
return eval(s.replace('x',x)
#Example:
>> func('x**2 + 3*x',1)
4
The first argument of the function func must be a string because the function eval accepts only string or code objects. However, I'd like to use this function in a kind of calculator, where the user types for example 2 + sin(2*pi-0.15) + func(1.8*x-32,273) and gets the answer of the expression, and it's annoying always to have to write the quotes before in the expression inside func().
Is there a way to make python understands the s argument is always a string, even when it's not between quotes?
No, it is not possible. You can't intercept the Python interpreter before it parses and evaluates 1.8*x-32.
Using eval as a glorified calculator is a highly questionable idea. The user could pass in all kinds of malicious Python code. If you're going to do it, you should provide as minimal an environment as possible for the code to run in. Pass in your own globals dict containing only the variables the user is allowed to reference.
return eval(s, {'x': x})
Besides being safer, this is also a better way to substitute x into the expression.
You could have it handle both cases:
def func(s, x=0):
if isinstance(s, basestring):
# x is in the scope, so you don't need to replace the string
return eval(s)
else:
return s
And the output:
>>> from math import *
>>> func('2 + sin(2*pi-0.15) + func(1.8*x-32,273)')
-30.1494381324736
>>> func('x**2 + 3*x', 1)
4
Caution: eval can do more than just add numbers. I can type __import__('os').system('rm /your/homework.doc') and your calculator will delete your homework.
In a word: no, if I understand you.
In a few more, you can sort of get around the problem by making x be a special object. This is how the Python math library SymPy works. For example:
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> x**2+3*x
x**2 + 3*x
>>> (x**2+3*x).subs(x,1)
4
There's even a handy function to turn strings into sympy objects:
>>> from sympy import sympify, pi
>>> sympify("x**2 - sin(x)")
x**2 - sin(x)
>>> _.subs(x, pi)
pi**2
All the warnings about untrusted user input hold. [I'm too lazy to check whether or not eval or exec is used on the sympify code path, and as they say, every weapon is loaded, even the unloaded ones.]
You can write an interpreter:
import code
def readfunc(prompt):
raw = input(prompt)
if raw.count(',')!=1:
print('Bad expression: {}'.format(raw))
return ''
s, x = raw.split(',')
return '''x={}; {}'''.format(x, s)
code.interact('Calc 0.1', readfunc)

Categories