Reputation: 754
I am trying to solve a system in Sympy of the form
max(a,b+c) == a^2
I would like for example, to tell Sympy to search for a solution where $max(a,b+c) = a$
and $max(a,b+c) = b+c$
. Is that possible in some way? I trying doing it through solve and solving a system of inequalities as in:
import sympy as sp
b = sp.Symbol('b', finite = True)
c = sp.Symbol('c', finite = True)
eq = sp.Max(a,b+c) - a**2
sp.solve([eq, a > b+c], a)
But I get the error:
The inequality, Eq(-x**2 + Max(x, _b + _c), 0), cannot be solved using solve_univariate_inequality.
Is there anyway such type of equations can be solved? Or can I at least substitute $Max(a,b+c)$
to some case at least to simplify the expression?
Upvotes: 0
Views: 762
Reputation: 1370
SymPy struggles solving equations with Min
and Max
. It is a little bit better at solving Piecewise
equalities but it is still not great. Here is how I would tackle this specific problem using rewrite(Piecewise)
:
from sympy import *
a, b, c = symbols('a b c', real=True)
eq = Max(a, b+c) - a**2
solution = solve(eq.rewrite(Piecewise), a)
print(solution)
This gives
[Piecewise((0, b <= -c), (nan, True)), Piecewise((1, b + c <= 1), (nan, True)), Piecewise((-sqrt(b + c), b + c > -sqrt(b + c)), (nan, True)), Piecewise((sqrt(b + c), b + c > sqrt(b + c)), (nan, True))]
So this tells you that SymPy found 4 solutions all conditional on what b
and c
are. They seem like valid solutions after plugging them in. I'm not sure if those are all the solutions though.
SymPy might struggle a lot more if equations are more complicated than this.
The solutions would probably look even better if you added positive=True
instead of real=True
in the code above. Always try to give as much information as possible when defining symbols.
Another route for solving these equations would be by substituting Max(a, b+c)
for a
and keep in mind that those solutions are for a >= b+c
and repeat for b+c >= a
. This would probably work better for more complicated equations.
For this specific example can do so by doing something like:
from sympy import *
a, b, c = symbols('a b c', real=True)
eq = Max(a, b+c) - a**2
eq1 = eq.subs(Max(a, b+c), a)
solution1 = solveset(eq1, a)
eq2 = eq.subs(Max(a, b+c), b+c)
solution2 = solveset(eq2, a)
solution = Piecewise((solution1, a > b+c), (solution2, a < b+c), (solution1.union(solution2), True))
print(solution)
Giving the same answer as above but a bit more readable:
Piecewise((FiniteSet(0, 1), a > b + c), (FiniteSet(sqrt(b + c), -sqrt(b + c)), a < b + c), (FiniteSet(0, 1, sqrt(b + c), -sqrt(b + c)), True))
Notice how you need to know the arguments of the Max
before hand and that there is only one Max
. Combining conditions with more than 1 max will be difficult especially since both solutions hold when they are equal.
I suggest this option if you are solving equations interactively instead of an in an automated fashion.
I haven't tested this one but I hope this provides the same answers in the more general case where you have multiple Max
varying arguments for each Max
. Each Max
can only take in 2 arguments though.
from sympy import *
a, b, c = symbols('a b c', real=True)
eq = Max(a, b+c) - a**2
eqs = [eq]
conditions = [True]
for f in preorder_traversal(eq):
new_eqs = []
new_conds = []
if f.func == Max:
for equation, condition in zip(eqs, conditions):
new_eqs.append(equation.subs(f, f.args[0]))
new_conds.append(And(condition, f.args[0] >= f.args[1]))
new_eqs.append(equation.subs(f, f.args[1]))
new_conds.append(And(condition, f.args[0] <= f.args[1]))
eqs = new_eqs
conditions = new_conds
solutions = []
for equation in eqs:
solutions.append(solveset(equation, a))
pieces = [(solution, condition) for solution, condition in zip(solutions, conditions)]
solution = Piecewise(*pieces)
print(solution)
This gives the same as above except for that last equality section:
Piecewise((FiniteSet(0, 1), a >= b + c), (FiniteSet(sqrt(b + c), -sqrt(b + c)), a <= b + c))
I could not combine both solutions when both of the inequalities hold so you just have to keep that in mind.
Upvotes: 2