dmortal
dmortal

Reputation: 599

Converting a string to a mathematical function: "name sint is not defined"

I have a function f(t,u,v) in string format; for example 't^2 * sint + u*(20 + t) + v*t'.

How can I solve this function?

I tried to do:

t = Symbol('t')
u = mu
v = mv
sol = eval(f)

But I get error saying name 'sint' is not defined

Upvotes: 1

Views: 435

Answers (2)

loxaxs
loxaxs

Reputation: 2289

This is rather ugly, but you could use regular expressions to (somewhat) format the expression before evaluating it. You'll probably have to hack around to adapt the below code to your needs.

import re
import textwrap
import math

functionBaseCode = textwrap.dedent("""
    def f({variables}):
        return {mathExpr}
    """)

def generateFunctionFromExpression(expression, variables):

    expression = expression.replace("^", "**")
    for fname in ["sin", "cos", "exp", "log", "sqrt"]:
         pattern = r"{fname} ?([a-zA-Z0-9]*)".format(fname = fname)
         replacement = r"math.{fname}(\1)".format(fname = fname)
         expression = re.sub(pattern, replacement, expression)

    variables = ", ".join(variables)
    mathExpr = expression
    funCode = functionBaseCode.format(
        variables = variables,
        mathExpr = mathExpr)

    # print(funCode)

    definitions = {}
    eval(compile(funCode, "<string>", "exec"), globals(), definitions)
    f = definitions["f"]

    return f

f = generateFunctionFromExpression("t^2 * sint + u*(20 + t) + v*t", "t u v".split())
g = generateFunctionFromExpression("x^2 + y^2", ["x", "y"])
# h = generateFunctionFromExpression("sqrt(x^2 + y^2)")
# l = generateFunctionFromExpression("log(sqrt(x)) - log(x) / 2", ["x"])
# h and l would fail because of the parenthesis after sqrt and log.

print(f(1, 1, 1)) # 22.8414
print(g(2, 3)) # 13

Upvotes: 0

user6655984
user6655984

Reputation:

Using eval is not the best approach. SymPy parser has options that allow for parsing strings with things like t^2 (called convert_xor) and sin t (called implicit_application). Here is an example:

from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_application, convert_xor
transformations = standard_transformations + (implicit_application, convert_xor)
f = parse_expr('t^2 * sin t + u*(20 + t) + v*t', transformations=transformations)

Now f is t**2*sin(t) + t*v + u*(t + 20) and you can work with it normally, for example

solve(f.subs({Symbol('u'): 4}), Symbol('v'))    # returns [-t*sin(t) - 4 - 80/t]

You may want to introduce u, v, t = symbols('u v t') to have easier access to those symbols.

Unfortunately sint will not be recognized as sin(t); the lack of space is fatal. This will have to be preprocessed, probably with regular expressions. For example,

import re
s = re.sub(r'\bsin', 'sin ', 't^2 * sint + u*(20 + t) + v*t')

leaves a space after each "sin" (extra space will not hurt).

Upvotes: 1

Related Questions