Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving _invert method in solveset #10971

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
45 changes: 43 additions & 2 deletions sympy/solvers/solveset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

from sympy.core.sympify import sympify
from sympy.core import S, Pow, Dummy, pi, Expr, Wild, Mul, Equality
from sympy.core.compatibility import ordered
from sympy.core.numbers import I, Number, Rational, oo
from sympy.core.function import (Lambda, expand, expand_complex)
from sympy.core.function import (Lambda, expand, expand_complex, Function)
from sympy.core.relational import Eq
from sympy.simplify.simplify import simplify, fraction, trigsimp
from sympy.simplify.simplify import simplify, fraction, trigsimp, powsimp
from sympy.simplify import powdenest
from sympy.core.symbol import Symbol
from sympy.functions import (log, Abs, tan, cot, sin, cos, sec, csc, exp,
acos, asin, acsc, asec, arg,
Expand All @@ -30,6 +32,11 @@
from sympy.utilities import filldedent


def _ispow(e):
"""Return True if e is a Pow or is exp."""
return isinstance(e, Expr) and (e.is_Pow or e.func is exp)


def _invert(f_x, y, x, domain=S.Complexes):
"""
Reduce the complex valued equation ``f(x) = y`` to a set of equations
Expand Down Expand Up @@ -136,6 +143,40 @@ def _invert_real(f, g_ys, symbol):
g, h = f.as_independent(symbol)
if g is not S.Zero:
return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol)
else:
if len(f.args) == 2 and g_ys == FiniteSet(0) and \
not f.is_polynomial(symbol):
lhs = f
rhs = FiniteSet(0)
a, b = ordered(f.args)
ai, ad = a.as_independent(symbol)
bi, bd = b.as_independent(symbol)
if any(_ispow(i) for i in (ad, bd)):
a_base, a_exp = ad.as_base_exp()
b_base, b_exp = bd.as_base_exp()
if a_base == b_base:
# a = -b
lhs = powsimp(powdenest(ad/bd))
rhs = -bi/ai
else:
rat = ad/bd
_lhs = powsimp(ad/bd)
if _lhs != rat:
lhs = _lhs
rhs = -bi/ai
if ai*bi is S.NegativeOne:
if all(
isinstance(i, Function) for i in (ad, bd)) and \
ad.func == bd.func and len(ad.args) == len(bd.args):
if len(ad.args) == 1:
lhs = ad.args[0] - bd.args[0]
else:
# should be able to solve
# f(x, y) == f(2, 3) -> x == 2
# f(x, x + y) == f(2, 3) -> x == 2 or x == 3 - y
raise NotImplementedError('equal function with more than 1 argument')
if lhs is not f:
return _invert_real(lhs - rhs, imageset(Lambda(n, n ), g_ys), symbol)

if f.is_Mul:
# f = g*h
Expand Down
11 changes: 8 additions & 3 deletions sympy/solvers/tests/test_solveset.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from sympy.sets import (FiniteSet, ConditionSet, Complement, ImageSet)

from sympy.utilities.pytest import XFAIL, raises, skip, slow
from sympy.utilities.pytest import XFAIL, raises, skip, slow, SKIP
from sympy.utilities.randtest import verify_numerically as tn
from sympy.physics.units import cm

Expand Down Expand Up @@ -593,9 +593,9 @@ def test_units():
def test_solve_only_exp_1():
y = Symbol('y', positive=True, finite=True)
assert solveset_real(exp(x) - y, x) == FiniteSet(log(y))
assert solveset_real(exp(x) + exp(-x) - y, x) != S.EmptySet
assert solveset_real(exp(x) + exp(-x) - 4, x) == \
FiniteSet(log(-sqrt(3) + 2), log(sqrt(3) + 2))
assert solveset_real(exp(x) + exp(-x) - y, x) != S.EmptySet


@XFAIL
Expand Down Expand Up @@ -909,7 +909,7 @@ def test_improve_coverage():
x = Symbol('x')
y = exp(x+1/x**2)
solution = solveset(y**2+y, x, S.Reals)
unsolved_object = ConditionSet(x, Eq((exp((x**3 + 1)/x**2) + 1)*exp((x**3 + 1)/x**2), 0), S.Reals)
unsolved_object = ConditionSet(x, Eq(exp(x + x**(-2)) + exp(2*x + 2/x**2), 0), S.Reals)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing is written in different way.

assert solution == unsolved_object

assert _has_rational_power(sin(x)*exp(x) + 1, x) == (False, S.One)
Expand Down Expand Up @@ -1086,3 +1086,8 @@ def test_issue_8715():
(Interval.open(-2, oo) - FiniteSet(0))
assert solveset(eq.subs(x,log(x)), x, S.Reals) == \
Interval.open(exp(-2), oo) - FiniteSet(1)


def test_issue_10864():
x =symbols('x' , positive = True)
assert solveset(x**(y*z) - x,x,S.Reals) == FiniteSet(1)