0

I want to extend the Symbols class in SymPy so that I can add a Boolean attribute. I’m able to accomplish this for a single symbol (see my question here, and also someone else’s question here). And the code to accomplish this is repeated below:

from sympy.core.symbol import Symbol
class State(Symbol):
    def __init__(self, name, boolean_attr):
        self.boolean_attr = boolean_attr
        super(State, self).__init__(name)

However, the problem with this solution is that when I am defining a polynomial, or some kind of expression involving more than one State, which is my extension of the Symbol class as you can see above, I need them all to be in the same domain when I evaluate it:

symbols defined separately cannot be evaluated numerically:

x=sympy.symbols('x')
y=sympy.symbols('y')
some_poly = Poly(x+y)
print some_poly.evalf(subs=dict(zip([sympy.symbols('x, y')],[1,4])))
>>> Poly(x + y, x, y, domain='ZZ')

symbols defined in the same domain can be evaluated numerically:

x, y = sympy.symbols('x, y')
some_poly = Poly(x+y)
print some_poly.evalf(subs=dict(zip(sympy.symbols('x,y'),[1,1])))
>>> 2.00000

Here is my question: How do I achieve this same behavior in my class State? Ideally it would work as follows:

x=State('x', boolean_attr=True)
y=State('y', boolean_attr=False)
states_poly = Poly(x+y)
print states_poly.evalf(subs=dict(zip(States('x,y'),[1,1])))
>>> 2.00000

But that doesn’t work because Sympy interprets x and y as being in different domains. How do I either:

  • get Sympy to interpret x and y as being in the same domain OR
  • extend the State class to be able to define symbols in the same domain, e.g.:

    x, y =State('x, y', boolean_attr=[True, False])

How do I allow my polynomials defined using my extended class to be evaluated numerically?

makansij
  • 9,303
  • 37
  • 105
  • 183

1 Answers1

1

In your first example you put symbols in a list so you didn't zip x and y with the values 1, 4:

>>> Poly(x+y).evalf(subs=dict(zip(sympy.symbols('x, y'),[1,4])))
5.00000000000000

You will get the desired result if you use the same State symbols that you defined

>>> x=State('x', boolean_attr=True)
... y=State('y', boolean_attr=False)
... states_poly = Poly(x+y)
... states_poly.evalf(subs=dict(zip((x,y),[1,1])))
2.00000000000000

(In your proposed syntax you used States which was undefined. Even if it did work, such a routine wouldn't have put True for one boolean_attr and False for the other and since Symbols match on attributes, the substitution would have failed.)

smichr
  • 16,948
  • 2
  • 27
  • 34
  • Ah, I can't believe it was that trivial! Thank you @smichr. The reason I had it wrapped in a list was because `zip(sympy.symbols('x'),[1])` doesn't work since `sympy.symbols('x')` is not iterable. But for multiple symbols it doesn't matter. – makansij Aug 05 '19 at 17:20
  • As perhaps a follow-up question, Is there then no difference between initializing together versus initializing separately: `x=sympy.symbols('x'), y=sympy.symbols('y')` and `x, y = sympy.symbols('x, y')` and my problems were just with using `zip` incorrectly. Is that right? – makansij Aug 05 '19 at 17:34
  • However, as your answer post indicates, there *is* a difference between `states_poly.evalf(subs=dict(zip((x,y),[1,1])))` and `states_poly.evalf(subs=dict(zip(sympy.symbols('x,y'),[1,1])))`. – makansij Aug 05 '19 at 18:05
  • `symbols('x,')` will create `(x,)` instead of `x`. And when initializing several variables at once, they all are created with the same attributes. – smichr Aug 07 '19 at 03:55
  • But if you already have x and y defined with some special attributes then`symbols('x,y')` is not creating the same Symbols, it creates 2 new Symbols which have the same name but different attributes and are this distinct. And that is why the substitution failed for you. – smichr Aug 07 '19 at 04:02