# Source code for sympy.assumptions.refine

from __future__ import print_function, division

from sympy.core import S, Add, Expr, Basic, Mul

[docs]def refine(expr, assumptions=True):
"""
Simplify an expression using assumptions.

Gives the form of expr that would be obtained if symbols
in it were replaced by explicit numerical expressions satisfying
the assumptions.

Examples
========

>>> from sympy import refine, sqrt, Q
>>> from sympy.abc import x
>>> refine(sqrt(x**2), Q.real(x))
Abs(x)
>>> refine(sqrt(x**2), Q.positive(x))
x

"""
if not isinstance(expr, Basic):
return expr
if not expr.is_Atom:
args = [refine(arg, assumptions) for arg in expr.args]
# TODO: this will probably not work with Integral or Polynomial
expr = expr.func(*args)
if hasattr(expr, '_eval_refine'):
ref_expr = expr._eval_refine(assumptions)
if ref_expr is not None:
return ref_expr
name = expr.__class__.__name__
handler = handlers_dict.get(name, None)
if handler is None:
return expr
new_expr = handler(expr, assumptions)
if (new_expr is None) or (expr == new_expr):
return expr
if not isinstance(new_expr, Expr):
return new_expr
return refine(new_expr, assumptions)

[docs]def refine_abs(expr, assumptions):
"""
Handler for the absolute value.

Examples
========

>>> from sympy import Symbol, Q, refine, Abs
>>> from sympy.assumptions.refine import refine_abs
>>> from sympy.abc import x
>>> refine_abs(Abs(x), Q.real(x))
>>> refine_abs(Abs(x), Q.positive(x))
x
>>> refine_abs(Abs(x), Q.negative(x))
-x

"""
from sympy.core.logic import fuzzy_not
from sympy import Abs
arg = expr.args[0]
# if it's nonnegative
return arg
return -arg
# arg is Mul
if isinstance(arg, Mul):
r = [refine(abs(a), assumptions) for a in arg.args]
non_abs = []
in_abs = []
for i in r:
if isinstance(i, Abs):
in_abs.append(i.args[0])
else:
non_abs.append(i)
return Mul(*non_abs) * Abs(Mul(*in_abs))

[docs]def refine_Pow(expr, assumptions):
"""
Handler for instances of Pow.

>>> from sympy import Symbol, Q
>>> from sympy.assumptions.refine import refine_Pow
>>> from sympy.abc import x,y,z
>>> refine_Pow((-1)**x, Q.real(x))
>>> refine_Pow((-1)**x, Q.even(x))
1
>>> refine_Pow((-1)**x, Q.odd(x))
-1

For powers of -1, even parts of the exponent can be simplified:

>>> refine_Pow((-1)**(x+y), Q.even(x))
(-1)**y
>>> refine_Pow((-1)**(x+y+z), Q.odd(x) & Q.odd(z))
(-1)**y
>>> refine_Pow((-1)**(x+y+2), Q.odd(x))
(-1)**(y + 1)
>>> refine_Pow((-1)**(x+3), True)
(-1)**(x + 1)

"""
from sympy.core import Pow, Rational
from sympy.functions.elementary.complexes import Abs
from sympy.functions import sign
if isinstance(expr.base, Abs):
return expr.base.args[0] ** expr.exp
if expr.base.is_number:
return abs(expr.base) ** expr.exp
return sign(expr.base) * abs(expr.base) ** expr.exp
if isinstance(expr.exp, Rational):
if type(expr.base) is Pow:
return abs(expr.base.base) ** (expr.base.exp * expr.exp)

if expr.base is S.NegativeOne:

old = expr

# For powers of (-1) we can remove
#  - even terms
#  - pairs of odd terms
#  - a single odd term + 1
#  - A numerical constant N can be replaced with mod(N,2)

terms = set(terms)
even_terms = set([])
odd_terms = set([])
initial_number_of_terms = len(terms)

for t in terms:

terms -= even_terms
if len(odd_terms) % 2:
terms -= odd_terms
new_coeff = (coeff + S.One) % 2
else:
terms -= odd_terms
new_coeff = coeff % 2

if new_coeff != coeff or len(terms) < initial_number_of_terms:

# Handle (-1)**((-1)**n/2 + m/2)
e2 = 2*expr.exp
if e2.could_extract_minus_sign():
e2 *= expr.base
i, p = e2.as_two_terms()
if p.is_Pow and p.base is S.NegativeOne:
i = (i + 1)/2
return expr.base**p.exp
return expr.base**(p.exp + 1)
else:
return expr.base**(p.exp + i)

if old != expr:
return expr

[docs]def refine_atan2(expr, assumptions):
"""
Handler for the atan2 function

Examples
========

>>> from sympy import Symbol, Q, refine, atan2
>>> from sympy.assumptions.refine import refine_atan2
>>> from sympy.abc import x, y
>>> refine_atan2(atan2(y,x), Q.real(y) & Q.positive(x))
atan(y/x)
>>> refine_atan2(atan2(y,x), Q.negative(y) & Q.negative(x))
atan(y/x) - pi
>>> refine_atan2(atan2(y,x), Q.positive(y) & Q.negative(x))
atan(y/x) + pi
>>> refine_atan2(atan2(y,x), Q.zero(y) & Q.negative(x))
pi
>>> refine_atan2(atan2(y,x), Q.positive(y) & Q.zero(x))
pi/2
>>> refine_atan2(atan2(y,x), Q.negative(y) & Q.zero(x))
-pi/2
>>> refine_atan2(atan2(y,x), Q.zero(y) & Q.zero(x))
nan
"""
from sympy.functions.elementary.trigonometric import atan
from sympy.core import S
y, x = expr.args
return atan(y / x)
return atan(y / x) - S.Pi
return atan(y / x) + S.Pi
return S.Pi
return S.Pi/2
return -S.Pi/2
return S.NaN
else:
return expr

[docs]def refine_Relational(expr, assumptions):
"""
Handler for Relational

>>> from sympy.assumptions.refine import refine_Relational
>>> from sympy.abc import x
>>> refine_Relational(x<0, ~Q.is_true(x<0))
False
"""

handlers_dict = {
'Abs': refine_abs,
'Pow': refine_Pow,
'atan2': refine_atan2,
'Equality': refine_Relational,
'Unequality': refine_Relational,
'GreaterThan': refine_Relational,
'LessThan': refine_Relational,
'StrictGreaterThan': refine_Relational,
'StrictLessThan': refine_Relational
}