1

I have the following formula that I would like to evaluate:

import math
import numpy as np
formula  = 'np.e**x + math.erf(x) + np.pi  +  math.erf(u)'

I can easily then evaluate the formula for given float values of x and u and eval() recognizes math.erf, np.pi and np.e. For example:

x=1.0; u=0.3; eval(formula)

yields 7.03. But, I want x and u to be arrays. I tried to use eval with a dictionary following this post.:

var = {'x':np.array([1,1]),'u':np.array([0.1,0.2])}
eval(formula, var)

which yields error messages, 'np' and 'math' are not defined, which was not the case above when eval was used without a dict. The same error messages are also obtained when 'x' and 'u' are set to floats instead of array with the var dictionary. Also, there are no problems if the dictionary is used with a 'formula' without np. and math., e.g. "

formula = 'x + u'. 

Does anybody have an idea how can I evaluate formula containing np.e, math.erf, etc., when x and u are arrays?

P.S. I am using Python 3.8.

Barmar
  • 741,623
  • 53
  • 500
  • 612
ogledala
  • 117
  • 4
  • 1
    Pass your dictionary as the locals, not globals. `eval(formula, locals=var)` – Barmar Dec 26 '22 at 22:58
  • var = {'x': np.array([1,1]), 'u': np.array([0.1,0.2]), 'np': np, 'math': math} result = eval(formula, var), this should help – Nish Dec 26 '22 at 23:06
  • 1
    Beside the point, but the `math` module doesn't operate on arrays, only scalar real numbers. – wjandrea Dec 26 '22 at 23:07
  • ^ numpy doesn't have an `erf`, but [scipy does](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.erf.html) – Pranav Hosangadi Dec 26 '22 at 23:15

1 Answers1

3

Passing var as globals to eval() means the global names np and math are not available to the expression (formula). Simply pass var as locals instead.

var = {'x': 1.0, 'u': 0.3}
eval(formula, None, var)  # -> 7.031202034457681

Note that this code doesn't work with arrays since the math module only works on scalars.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 1
    Wouldn't it be easier with named arguments, so you don't have to specify `None` as the globals? – Barmar Dec 26 '22 at 23:15
  • @Barmar Yeah, but `eval()` doesn't take any keyword arguments. Although, [the docs](https://docs.python.org/3/library/functions.html#eval) say it does. Looks like a documentation bug. – wjandrea Dec 26 '22 at 23:17
  • Looks like a version issue. `help(eval)` in 3.9 shows `eval(source, globals=None, locals=None, /)`. It changed to `eval(expression, /, globals=None, locals=None)` in 3.11. – Barmar Dec 26 '22 at 23:32
  • @Barmar `help(eval)` in 3.11 still shows `eval(source, globals=None, locals=None, /)`. (I installed it just to check this, lol.) The problem is that the docs don't agree with `help()`. I opened [a bug about it](https://github.com/python/cpython/issues/100546). – wjandrea Dec 26 '22 at 23:46
  • Thanks, @wjandrea, this solved the problem (at least in 3.8). With scipy's erf, can also do arrays. – ogledala Dec 27 '22 at 21:10