Source code for sympy.assumptions.refine

from __future__ import print_function, division

from sympy.core import S, Add, Expr, Basic, Mul
from sympy.assumptions import Q, ask

[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 ask(Q.real(arg), assumptions) and \ fuzzy_not(ask(Q.negative(arg), assumptions)): # if it's nonnegative return arg if ask(Q.negative(arg), assumptions): 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): if ask(Q.real(expr.base.args[0]), assumptions) and \ ask(Q.even(expr.exp), assumptions): return expr.base.args[0] ** expr.exp if ask(Q.real(expr.base), assumptions): if expr.base.is_number: if ask(Q.even(expr.exp), assumptions): return abs(expr.base) ** expr.exp if ask(Q.odd(expr.exp), assumptions): 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: if expr.exp.is_Add: 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) coeff, terms = expr.exp.as_coeff_add() terms = set(terms) even_terms = set([]) odd_terms = set([]) initial_number_of_terms = len(terms) for t in terms: if ask(Q.even(t), assumptions): even_terms.add(t) elif ask(Q.odd(t), assumptions): odd_terms.add(t) 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: terms.add(new_coeff) expr = expr.base**(Add(*terms)) # Handle (-1)**((-1)**n/2 + m/2) e2 = 2*expr.exp if ask(Q.even(e2), assumptions): if e2.could_extract_minus_sign(): e2 *= expr.base if e2.is_Add: i, p = e2.as_two_terms() if p.is_Pow and p.base is S.NegativeOne: if ask(Q.integer(p.exp), assumptions): i = (i + 1)/2 if ask(Q.even(i), assumptions): return expr.base**p.exp elif ask(Q.odd(i), assumptions): 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 if ask(Q.real(y) & Q.positive(x), assumptions): return atan(y / x) elif ask(Q.negative(y) & Q.negative(x), assumptions): return atan(y / x) - S.Pi elif ask(Q.positive(y) & Q.negative(x), assumptions): return atan(y / x) + S.Pi elif ask(Q.zero(y) & Q.negative(x), assumptions): return S.Pi elif ask(Q.positive(y) & Q.zero(x), assumptions): return S.Pi/2 elif ask(Q.negative(y) & Q.zero(x), assumptions): return -S.Pi/2 elif ask(Q.zero(y) & Q.zero(x), assumptions): return S.NaN else: return expr
[docs]def refine_Relational(expr, assumptions): """ Handler for Relational >>> from sympy.assumptions.refine import refine_Relational >>> from sympy.assumptions.ask import Q >>> from sympy.abc import x >>> refine_Relational(x<0, ~Q.is_true(x<0)) False """ return ask(Q.is_true(expr), assumptions)
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 }