Sympy substitutions using strings subs('x', 'w') instead of symbols subs(x, w)

805 views Asked by At

I'm working on an application with a circuit simulator ahkab, and long story short I need to substitute the laplace variable s in some equations with 1j*w. It is much more convenient for me to perform this substitution and others using the names of symbols rather than the symbols themselves. I have come across some odd behaviour.

If you do

    >>> x = Symbol('x')
    >>> y = Symbol('y')
    >>> expr = x + y
    x + y
    >>> expr.subs('x', 'w')
    w + y

Which seems to work as I expect. The problem comes with the symbol is declared with complex = True, here

    >>> s = Symbol('s', complex = True)
    >>> y = Symbol('y')
    >>> expr = s + y
    s + y
    >>> expr.subs(s, 'w') #Works as expected
    w + y
    >>> expr.subs('s', 'w') #Has no effect, this is my problem.
    s + y

I haven't been able to find information about substitutions in this manner in the docs. To me this seems like a bug, but I don't know what the behaviour should be.

2

There are 2 answers

0
ptb On BEST ANSWER

subs calls sympify on it arguments. See https://github.com/sympy/sympy/blob/master/sympy/core/basic.py#L845 for example. This means that strings will be converted to symbols but sympify has no way of knowing that you want your strings to be converted to symbols with non-default assumptions. The only way to do that is to actually pass in the symbol. Note that symbols with different assumptions are not considered equal.

In [1]: from sympy import Symbol

In [2]: x = Symbol('s')

In [3]: y = Symbol('s')

In [4]: x == y
Out[4]: True

In [5]: y = Symbol('s', complex=True)

In [6]: x == y
Out[6]: False
0
Bjoern Dahlgren On

I would suggest that you keep track of all Symbol instances in a dictionary. You may make a specialized dictionary e.g.:

from sympy import Symbol as _Symbol

class SymbolCollection(dict):
    def __missing__(self, key):
        value = self[key] = _Symbol(key)
        return value

symbs = SymbolCollection()
def Symbol(key, *args, **kwargs):
    s = _Symbol(key, *args, **kwargs)
    symbs[key] = s
    return s

applied to your example:

>>> s = Symbol('s', complex = True)
>>> y = Symbol('y')
>>> expr = s + y
>>> expr
s + y
>>> expr.subs(s, symbs['w'])
w + y
>>> expr.subs(symbs['s'], symbs['w'])
w + y

If the solution is too verbose I would suggest writing a specialized subs function and pass expr explicitly as first argument instead of relying on the method .subs