Sympy evalf for real symbol

Viewed 32

This Sympy code works as I expect:

>>> x = sp.Symbol("x")
>>> y = sp.Symbol("y")
>>> z = sp.Symbol("z")
>>> (x+y+z).evalf(subs={"x":1, "y":2, "z":3})
6.0

However, if I use real-valued Symbols instead, the expression isn't simplified:

>>> x = sp.Symbol("x", real=True)
>>> y = sp.Symbol("y", real=True)
>>> z = sp.Symbol("z", real=True)
>>> (x+y+z).evalf(subs={"x":1, "y":2, "z":3})
x + y + z

I was unable to find an explanation for this by searching with keywords like sympy symbol real evalf - I only get unrelated results.

Why isn't the expression simplified in the second case? How can I substitute in values for real-valued Symbols and evaluate the expression?

1 Answers

Use the symbols as keys for the dictionary of substitutions, rather than string names:

>>> (x + y + z).evalf(subs={x: 1, y: 2, z: 3})
6.00000000000000

There appears to be an inconsistency between how complex and real symbols are treated:

>>> x = sp.Symbol('x')
>>> x.subs(x, 1)
1
>>> x.subs('x', 1)
1
>>> x = sp.Symbol('x', real=True)
>>> x.subs(x, 1)
1
>>> x.subs('x', 1)
x

I can't find anything relevant about this in the documentation, and the built-in help text isn't useful either. My best guess is that a string 'x' is naively converted using sp.Symbol, and the resulting symbol is always a complex-valued symbol that doesn't match the real-valued one with the same name.

I would consider this behaviour a bug and file a bug report (or look for an existing report). IMO, if a string is usable at all, it should match any symbol with that name; and an expression shouldn't be able to contain two different variables with the same name and different types; and trying to substitute in a variable with a matching name and incompatible type should probably raise an exception:

>>> x = sp.Symbol('x')
>>> # why allow this?
>>> broken = sp.Symbol('x', real=True) + x
>>> broken # if the types matched, it would simplify to 2*x
x + x
>>> # surely 2 is the only value that makes sense?
>>> broken.subs('x', 1)
x + 1
>>> x.subs('x', 1)
1
>>> # If this is allowed at all, surely the result should be 1?
>>> x.subs(sp.Symbol('x', real=True), 1)
x
Related