Skip to content

Commit

Permalink
ignore assumptions in solveset
Browse files Browse the repository at this point in the history
  • Loading branch information
smichr committed Jun 23, 2020
1 parent 93efcb1 commit a7ce72d
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 70 deletions.
46 changes: 27 additions & 19 deletions sympy/solvers/solveset.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from sympy.core import (S, Pow, Dummy, pi, Expr, Wild, Mul, Equality,
Add)
from sympy.core.containers import Tuple
from sympy.core.facts import InconsistentAssumptions
from sympy.core.numbers import I, Number, Rational, oo
from sympy.core.function import (Lambda, expand_complex, AppliedUndef,
expand_log, _mexpand)
Expand Down Expand Up @@ -63,6 +62,9 @@ class NonlinearError(ValueError):
pass


_rc = Dummy("R", real=True), Dummy("C", complex=True)


def _masked(f, *atoms):
"""Return ``f``, with all objects given by ``atoms`` replaced with
Dummy symbols, ``d``, and the list of replacements, ``(d, e)``,
Expand Down Expand Up @@ -1994,7 +1996,7 @@ def solveset(f, symbol=None, domain=S.Complexes):
Examples
========
>>> from sympy import exp, sin, Symbol, pprint, S
>>> from sympy import exp, sin, Symbol, pprint, S, Eq
>>> from sympy.solvers.solveset import solveset, solveset_real
* The default domain is complex. Not specifying a domain will lead
Expand All @@ -2020,15 +2022,18 @@ def solveset(f, symbol=None, domain=S.Complexes):
>>> solveset_real(exp(x) - 1, x)
FiniteSet(0)
The solution is mostly unaffected by assumptions on the symbol,
but there may be some slight difference:
>>> pprint(solveset(sin(x)/x,x), use_unicode=False)
({2*n*pi | n in Integers} \ {0}) U ({2*n*pi + pi | n in Integers} \ {0})
The solution is unaffected by assumptions on the symbol:
>>> p = Symbol('p', positive=True)
>>> pprint(solveset(sin(p)/p, p), use_unicode=False)
{2*n*pi | n in Integers} U {2*n*pi + pi | n in Integers}
>>> pprint(solveset(p**2 - 4))
{-2, 2}
When a conditionSet is returned, symbols with assumptions that
would alter the set are replaced with more generic symbols:
>>> i = Symbol('i', imaginary=True)
>>> solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals)
ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals)
* Inequalities can be solved over the real domain only. Use of a complex
domain leads to a NotImplementedError.
Expand Down Expand Up @@ -2079,16 +2084,19 @@ def solveset(f, symbol=None, domain=S.Complexes):
# the xreplace will be needed if a ConditionSet is returned
return solveset(f[0], s[0], domain).xreplace(swap)

if domain.is_subset(S.Reals):
if not symbol.is_real:
assumptions = symbol.assumptions0
assumptions['real'] = True
try:
r = Dummy('r', **assumptions)
return solveset(f.xreplace({symbol: r}), r, domain
).xreplace({r: symbol})
except InconsistentAssumptions:
pass
# solveset should ignore assumptions on symbols
if symbol not in _rc:
x = _rc[0] if domain.is_subset(S.Reals) else _rc[1]
rv = solveset(f.xreplace({symbol: x}), x, domain)
# try to use the original symbol if possible
try:
_rv = rv.xreplace({x: symbol})
except TypeError:
_rv = rv
if rv.dummy_eq(_rv):
rv = _rv
return rv

# Abs has its own handling method which avoids the
# rewriting property that the first piece of abs(x)
# is for x >= 0 and the 2nd piece for x < 0 -- solutions
Expand Down
116 changes: 65 additions & 51 deletions sympy/solvers/tests/test_solveset.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,7 @@ def test_solve_polynomial():
assert solveset_real(x**Rational(1, 3) - 3, x) == FiniteSet(27)
assert len(solveset_real(x**5 + x**3 + 1, x)) == 1
assert len(solveset_real(-2*x**3 + 4*x**2 - 2*x + 6, x)) > 0

assert solveset_real(x**6 + x**4 + I, x) == ConditionSet(x,
Eq(x**6 + x**4 + I, 0), S.Reals)
assert solveset_real(x**6 + x**4 + I, x) is S.EmptySet


def test_return_root_of():
Expand Down Expand Up @@ -607,7 +605,8 @@ def test_poly_gens():
def test_solve_abs():
n = Dummy('n')
raises(ValueError, lambda: solveset(Abs(x) - 1, x))
assert solveset(Abs(x) - n, x, S.Reals) == ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n})
assert solveset(Abs(x) - n, x, S.Reals).dummy_eq(
ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n}))
assert solveset_real(Abs(x) - 2, x) == FiniteSet(-2, 2)
assert solveset_real(Abs(x) + 2, x) is S.EmptySet
assert solveset_real(Abs(x + 3) - 2*Abs(x - 3), x) == \
Expand Down Expand Up @@ -953,10 +952,11 @@ def test_solve_hyperbolic():
ImageSet(Lambda(n, n*pi/4 - 11*pi/16 + E), S.Integers)))

# issues #18490 / #19489
assert solveset(cosh(x) + cosh(3*x) - cosh(5*x), x, S.Reals) == \
ConditionSet(x, Eq(cosh(x) + cosh(3*x) - cosh(5*x), 0), S.Reals)
assert solveset(sinh(8*x) + coth(12*x)) == ConditionSet(
x, Eq(sinh(8*x) + coth(12*x), 0), S.Complexes)
assert solveset(cosh(x) + cosh(3*x) - cosh(5*x), x, S.Reals
).dummy_eq(ConditionSet(x,
Eq(cosh(x) + cosh(3*x) - cosh(5*x), 0), S.Reals))
assert solveset(sinh(8*x) + coth(12*x)).dummy_eq(
ConditionSet(x, Eq(sinh(8*x) + coth(12*x), 0), S.Complexes))


def test_solve_trig_hyp_symbolic():
Expand Down Expand Up @@ -1211,23 +1211,23 @@ def test__solveset_multi():


def test_conditionset():
assert solveset(Eq(sin(x)**2 + cos(x)**2, 1), x, domain=S.Reals) == \
ConditionSet(x, True, S.Reals)
assert solveset(Eq(sin(x)**2 + cos(x)**2, 1), x, domain=S.Reals
) is S.Reals

assert solveset(Eq(x**2 + x*sin(x), 1), x, domain=S.Reals
) == ConditionSet(x, Eq(x**2 + x*sin(x) - 1, 0), S.Reals)
).dummy_eq(ConditionSet(x, Eq(x**2 + x*sin(x) - 1, 0), S.Reals))

assert dumeq(solveset(Eq(-I*(exp(I*x) - exp(-I*x))/2, 1), x
), imageset(Lambda(n, 2*n*pi + pi/2), S.Integers))

assert solveset(x + sin(x) > 1, x, domain=S.Reals
) == ConditionSet(x, x + sin(x) > 1, S.Reals)
).dummy_eq(ConditionSet(x, x + sin(x) > 1, S.Reals))

assert solveset(Eq(sin(Abs(x)), x), x, domain=S.Reals
) == ConditionSet(x, Eq(-x + sin(Abs(x)), 0), S.Reals)
).dummy_eq(ConditionSet(x, Eq(-x + sin(Abs(x)), 0), S.Reals))

assert solveset(y**x-z, x, S.Reals) == \
ConditionSet(x, Eq(y**x - z, 0), S.Reals)
assert solveset(y**x-z, x, S.Reals
).dummy_eq(ConditionSet(x, Eq(y**x - z, 0), S.Reals))


@XFAIL
Expand All @@ -1246,7 +1246,7 @@ def test_improve_coverage():
from sympy.solvers.solveset import _has_rational_power
solution = solveset(exp(x) + sin(x), x, S.Reals)
unsolved_object = ConditionSet(x, Eq(exp(x) + sin(x), 0), S.Reals)
assert solution == unsolved_object
assert solution.dummy_eq(unsolved_object)

assert _has_rational_power(sin(x)*exp(x) + 1, x) == (False, S.One)
assert _has_rational_power((sin(x)**2)*(exp(x) + 1)**3, x) == (False, S.One)
Expand Down Expand Up @@ -1899,10 +1899,10 @@ def test_simplification():
def test_issue_10555():
f = Function('f')
g = Function('g')
assert solveset(f(x) - pi/2, x, S.Reals) == \
ConditionSet(x, Eq(f(x) - pi/2, 0), S.Reals)
assert solveset(f(g(x)) - pi/2, g(x), S.Reals) == \
ConditionSet(g(x), Eq(f(g(x)) - pi/2, 0), S.Reals)
assert solveset(f(x) - pi/2, x, S.Reals).dummy_eq(
ConditionSet(x, Eq(f(x) - pi/2, 0), S.Reals))
assert solveset(f(g(x)) - pi/2, g(x), S.Reals).dummy_eq(
ConditionSet(g(x), Eq(f(g(x)) - pi/2, 0), S.Reals))


def test_issue_8715():
Expand Down Expand Up @@ -2092,7 +2092,8 @@ def test_exponential_real():
assert solveset_real(x**2 - y**2/exp(x), y) == Intersection(
S.Reals, FiniteSet(-sqrt(x**2*exp(x)), sqrt(x**2*exp(x))))
p = Symbol('p', positive=True)
assert solveset_real((1/p + 1)**(p + 1), p) == EmptySet()
assert solveset_real((1/p + 1)**(p + 1), p).dummy_eq(
ConditionSet(x, Eq((1 + 1/x)**(x + 1), 0), S.Reals))


@XFAIL
Expand Down Expand Up @@ -2134,16 +2135,16 @@ def test_expo_conditionset():
f4 = log(x) - exp(x)
f5 = 2**x + 3**x - 5**x

assert solveset(f1, x, S.Reals) == ConditionSet(
x, Eq((exp(x) + 1)**x - 2, 0), S.Reals)
assert solveset(f2, x, S.Reals) == ConditionSet(
x, Eq(x*(x + 2)**y - 3, 0), S.Reals)
assert solveset(f3, x, S.Reals) == ConditionSet(
x, Eq(2**x - exp(x) - 3, 0), S.Reals)
assert solveset(f4, x, S.Reals) == ConditionSet(
x, Eq(-exp(x) + log(x), 0), S.Reals)
assert solveset(f5, x, S.Reals) == ConditionSet(
x, Eq(2**x + 3**x - 5**x, 0), S.Reals)
assert solveset(f1, x, S.Reals).dummy_eq(ConditionSet(
x, Eq((exp(x) + 1)**x - 2, 0), S.Reals))
assert solveset(f2, x, S.Reals).dummy_eq(ConditionSet(
x, Eq(x*(x + 2)**y - 3, 0), S.Reals))
assert solveset(f3, x, S.Reals).dummy_eq(ConditionSet(
x, Eq(2**x - exp(x) - 3, 0), S.Reals))
assert solveset(f4, x, S.Reals).dummy_eq(ConditionSet(
x, Eq(-exp(x) + log(x), 0), S.Reals))
assert solveset(f5, x, S.Reals).dummy_eq(ConditionSet(
x, Eq(2**x + 3**x - 5**x, 0), S.Reals))


def test_exponential_symbols():
Expand All @@ -2156,18 +2157,25 @@ def test_exponential_symbols():
f2 = (x/y)**w - 2
sol1 = Intersection({log(2)/(log(x) - log(y))}, S.Reals)
sol2 = Intersection({log(2)/log(x/y)}, S.Reals)
assert solveset(f1, w, S.Reals) == sol1
assert solveset(f2, w, S.Reals) == sol2
assert solveset(f1, w, S.Reals) == sol1, solveset(f1, w, S.Reals)
assert solveset(f2, w, S.Reals) == sol2, solveset(f2, w, S.Reals)

assert solveset(x**x, x, S.Reals) == S.EmptySet
assert solveset(x**x, x, Interval.Lopen(0,oo)).dummy_eq(
ConditionSet(w, Eq(w**w, 0), Interval.open(0, oo)))
assert solveset(x**y - 1, y, S.Reals) == FiniteSet(0)
assert solveset(exp(x/y)*exp(-z/y) - 2, y, S.Reals) == FiniteSet(
(x - z)/log(2)) - FiniteSet(0)

assert solveset_real(a**x - b**x, x) == ConditionSet(
x, (a > 0) & (b > 0), FiniteSet(0))
assert solveset(a**x - b**x, x) == ConditionSet(
x, Ne(a, 0) & Ne(b, 0), FiniteSet(0))
assert solveset(a**x - b**x, x).dummy_eq(ConditionSet(
w, Ne(a, 0) & Ne(b, 0), FiniteSet(0)))


def test_ignore_assumptions():
# make sure assumptions are ignored
xpos = symbols('x', positive=True)
x = symbols('x')
assert solveset_complex(xpos**2 - 4, xpos
) == solveset_complex(x**2 - 4, x)


@XFAIL
Expand Down Expand Up @@ -2322,16 +2330,20 @@ def test_invert_modular():
def test_solve_modular():
n = Dummy('n', integer=True)
# if rhs has symbol (need to be implemented in future).
assert solveset(Mod(x, 4) - x, x, S.Integers) == \
ConditionSet(x, Eq(-x + Mod(x, 4), 0), \
S.Integers)
assert solveset(Mod(x, 4) - x, x, S.Integers
).dummy_eq(
ConditionSet(x, Eq(-x + Mod(x, 4), 0),
S.Integers))
# when _invert_modular fails to invert
assert solveset(3 - Mod(sin(x), 7), x, S.Integers) == \
ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), S.Integers)
assert solveset(3 - Mod(log(x), 7), x, S.Integers) == \
ConditionSet(x, Eq(Mod(log(x), 7) - 3, 0), S.Integers)
assert solveset(3 - Mod(exp(x), 7), x, S.Integers) == \
ConditionSet(x, Eq(Mod(exp(x), 7) - 3, 0), S.Integers)
assert solveset(3 - Mod(sin(x), 7), x, S.Integers
).dummy_eq(
ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), S.Integers))
assert solveset(3 - Mod(log(x), 7), x, S.Integers
).dummy_eq(
ConditionSet(x, Eq(Mod(log(x), 7) - 3, 0), S.Integers))
assert solveset(3 - Mod(exp(x), 7), x, S.Integers
).dummy_eq(ConditionSet(x, Eq(Mod(exp(x), 7) - 3, 0),
S.Integers))
# EmptySet solution definitely
assert solveset(7 - Mod(x, 5), x, S.Integers) == EmptySet()
assert solveset(5 - Mod(x, 5), x, S.Integers) == EmptySet()
Expand Down Expand Up @@ -2387,10 +2399,12 @@ def test_solve_modular():
# Complex args
assert solveset(Mod(x, 3) - I, x, S.Integers) == \
EmptySet()
assert solveset(Mod(I*x, 3) - 2, x, S.Integers) == \
ConditionSet(x, Eq(Mod(I*x, 3) - 2, 0), S.Integers)
assert solveset(Mod(I + x, 3) - 2, x, S.Integers) == \
ConditionSet(x, Eq(Mod(x + I, 3) - 2, 0), S.Integers)
assert solveset(Mod(I*x, 3) - 2, x, S.Integers
).dummy_eq(
ConditionSet(x, Eq(Mod(I*x, 3) - 2, 0), S.Integers))
assert solveset(Mod(I + x, 3) - 2, x, S.Integers
).dummy_eq(
ConditionSet(x, Eq(Mod(x + I, 3) - 2, 0), S.Integers))

# issue 17373 (https://github.com/sympy/sympy/issues/17373)
assert dumeq(solveset(Mod(x**4, 14) - 11, x, S.Integers),
Expand Down

0 comments on commit a7ce72d

Please sign in to comment.