I’m using python, and I want a function that takes a string containing a mathematical expression of one variable (x) and returns a function that evaluates that expression using lambdas. Syntax should be such:
f = f_of_x("sin(pi*x)/(1+x**2)")
print f(0.5)
0.8
syntax should allow ( ) as well as [ ] and use standard operator precedence. Trig functions should have precedence lower than multiplication and higher than addition. Hence the string ‘sin 2x + 1’ would be equivalent to sin(2x)+1, though both are valid. This is for evaluating user input of algebraic and trigonometric expressions, so think math syntax not programming syntax. The list of supported functions should be easily extensible and the code should be clear and easy to understand. It’s OK not to collapse constant expressions.
The sample function here is incomplete. It takes a nested list representing the expression and generates an appropriate function. While somewhat easy to understand, even this seems ugly for python.
import math
def f_of_x(op):
if (isinstance((op[0]), (int, long, float, complex)) ):
return (lambda x:op[0])
elif op[0]=="pi": return lambda x: 3.14159265358979
elif op[0]=="e": return lambda x: 2.718281828459
elif op[0]=="x": return lambda x: x
elif op[0]=="sin": return lambda x: math.sin(f_of_x(op[1])(x))
elif op[0]=="cos": return lambda x: math.cos(f_of_x(op[1])(x))
elif op[0]=="tan": return lambda x: math.tan(f_of_x(op[1])(x))
elif op[0]=="sqrt": return lambda x: math.sqrt(f_of_x(op[1])(x))
elif op[0]=="+": return lambda x: (f_of_x(op[1])(x))+(f_of_x(op[2])(x))
elif op[0]=="-": return lambda x: (f_of_x(op[1])(x))-(f_of_x(op[2])(x))
elif op[0]=="*": return lambda x: (f_of_x(op[1])(x))*(f_of_x(op[2])(x))
elif op[0]=="/": return lambda x: (f_of_x(op[1])(x))/(f_of_x(op[2])(x))
elif op[0]=="**": return lambda x: (f_of_x(op[1])(x))**(f_of_x(op[2])(x))
# should never get here with well formed input
return
def test():
# test function f(x) = sin(pi*x)/(1+x**2)
s = ['/',['sin',['*',['pi'],['x']]],['+',[1],['**',['x'],[2]]]]
f = f_of_x(s)
for x in range(30):
print " "*int(f(x*0.2)*30+10)+"x"
As a general guideline, think of your solution as a tutorial on lambdas and parsers – not code golf. The sample code is just that, so write what you feel is clearest.
How about this:
It can easily be made to support
[]as well as()and uses standard operator precedence. It does not let you use trig functions without parens, though, nor does it let you imply multiplication by juxtaposition (like2x). The list of supported functions is easily extensible, however, and the code is probably as clear and easy to understand as you can get.If you absolutely need the extra features, look at http://christophe.delord.free.fr/tpg/. The example given on that page can be easily modified to do everything you want.