Search code examples
sympysymbolic-math

Simplify expression with assumptions involving relations between variables in SymPy


Is it possible to simplify an expression in SymPy, if we know that variables satisfy certain equation? For example in Mathematica we can write something like this:

Simplify[a+b-c, a+b==c]

Of course in this case it is possible to solve for a and make a substitution. However, for the long expressions making a global substitution might not make a sense. If the goal is to produce the shortest expression possible, one might need to apply substitution for the certain terms and leave the rest untouched or solve for b instead of a.

I think sympy.assumptions module cannot impose restrictions mutually on the several variables. Is it possible to achieve the functionality of Mathematica's Simplify[expr, assum] in any other way in SymPy?

Or is there any other open-source project which can do something like this?


Solution

  • SymPy's current assumptions system can not handle relationships between variables although that is being worked on. There are a couple of ways that you can do this though.

    The ratsimpmodprime function simplifies an expression that is polynomial in some symbols based on knowing that the symbols themselves satisfy polynomial equations. We can use this to make a function that simplifies the example you showed:

    In [26]: a, b, c = symbols('a:c')
    
    In [27]: polysimp = lambda expr, eqs: ratsimpmodprime(expr, groebner(eqs).exprs)
    
    In [28]: polysimp(a + b - c, [a + b - c])
    Out[28]: 0
    
    In [29]: polysimp(a + b, [a + b - c])
    Out[29]: c
    
    In [31]: polysimp(a**4 + b - c, [a**2 - b, b - c])
    Out[31]: 
     2
    c 
    

    You can also introduce a new symbol and solve for that along with the other equations as a combined system:

    In [33]: solve([z - (a + b - c), a + b - c])[z]
    Out[33]: 0
    

    This method has the advantage that you can choose which symbols you want to eliminate e.g.:

    In [38]: solve([z - (a + b), a + b - c], [z, c])[z]
    Out[38]: a + b
    
    In [39]: solve([z - (a + b), a + b - c], [z, b])[z]
    Out[39]: c
    

    Either answer is valid since a + b == c so the expected output from "simplifying" is ambiguous.