Weird issue found trying to match a expression with a input that has paranthesis without evaluating(Sympy)

Viewed 40

I have gone into detail in this issue thread https://github.com/sympy/sympy/issues/23709

but the gist is that I am trying to get the coefficients of an equation in the form:

parsed_input = 7*x + 4*(10*x + 6) >= 8*x + 15

I am using the pattern:

x = Wild("x",  properties=[lambda x: isinstance(x, Symbol)])
a = Wild("a",  properties=[lambda x: isinstance(x, Integer)])
p = Wild("p",  properties=[lambda x: isinstance(x, Integer)])
q = Wild("q",  properties=[lambda x: isinstance(x, Integer)])
b = Wild("b",  properties=[lambda x: isinstance(x, Integer)])
c = Wild("c",  properties=[lambda x: isinstance(x, Integer)])
r = Wild("r",  properties=[lambda x: isinstance(x, Integer)])
s = Wild("s",  properties=[lambda x: isinstance(x, Integer)])

expected_output = Ge(Mul(a, (p*x + q)) +b*x + c,  r*x + s)

But when I do:

matching = parsed_input.match(expected_output)

I am mostly getting a=1 , p=40, q=24 and some other times I get a=4,p=10, q=6

How can I get a=4,p=10, q=6 everytime?

1 Answers

Sometimes a custom parser can help:

def parse(eq,x=None):
    from sympy import Add, ordered
    from sympy.utilities.iterables import sift
    if x is None:
        from sympy.abc import x
    bcxd, axe = sift(Add.make_args(eq), lambda _: _.has(Add), binary=True)
    if len(bcxd) == 2:
        axe, bcxd = [[i] for i in bcxd]
        if axe[0].is_Mul:
            axe, bcxd = bcxd, axe
    assert len(bcxd) < 2
    assert len(axe) < 3
    e, ax = Add(*axe).as_coeff_Add()
    if not ax:
        a = 0
    else:
        a,X = ax.as_coeff_Mul()
        assert X == x
    if not bcxd:
        b=c=d=0    
    else:
        bcxd = bcxd.pop()
        if bcxd.is_Add:
            b = 1
            cxd = bcxd
        else:
            b,cxd = ordered(bcxd.args)
        if cxd.is_Mul:
            d = 0
            cx = cxd
        else:
            d,cx = ordered(cxd.args)
        c,X = cx.as_independent(x, as_Add=False)
        if X == 1:
            c,d=0,c
        else:
            assert X == x
    return dict(zip('abcde',(a,b,c,d,e)))

from sympy import S
from sympy.abc import x
assert parse(S(3)) == {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 3}
assert parse(x) == {'a': 1, 'b': 0, 'c': 0, 'd': 0, 'e': 0}
assert parse(3*x) == {'a': 3, 'b': 0, 'c': 0, 'd': 0, 'e': 0}
assert parse(3*x+4) == {'a': 3, 'b': 0, 'c': 0, 'd': 0, 'e': 4}
assert parse(3*x+4+Mul(1,x+7,evaluate=False)) == {'a': 3, 'b': 1, 'c': 1, 'd': 7, 'e': 4}
assert parse(3*x+4+Mul(1,2*x+7,evaluate=False)) == {'a': 3, 'b': 1, 'c': 2, 'd': 7, 'e': 4}
assert parse(3*x+4+Mul(6,2*x+7,evaluate=False)) == {'a': 3, 'b': 6, 'c': 2, 'd': 7, 'e': 4}
with evaluate(False):
    eq = 2+3*x+4*(5*x+6)

assert parse(eq) == dict(zip('abcde', (3,4,5,6,2)))
Related