def MatPow(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if int_exp: return ask(Q.unitary(base), assumptions) return None
def Basic(expr, assumptions): _integer = ask(Q.integer(expr), assumptions) if _integer: _even = ask(Q.even(expr), assumptions) if _even is None: return None return not _even return _integer
def Mul(expr, assumptions): """ Even * Integer -> Even Even * Odd -> Even Integer * Odd -> ? Odd * Odd -> Odd """ if expr.is_number: return AskEvenHandler._number(expr, assumptions) even, odd, irrational = False, 0, False for arg in expr.args: # check for all integers and at least one even if ask(Q.integer(arg), assumptions): if ask(Q.even(arg), assumptions): even = True elif ask(Q.odd(arg), assumptions): odd += 1 elif ask(Q.irrational(arg), assumptions): # one irrational makes the result False # two makes it undefined if irrational: break irrational = True else: break else: if irrational: return False if even: return True if odd == len(expr.args): return False
def Mul(expr, assumptions): """ Return True if expr is bounded, False if not and None if unknown. TRUTH TABLE B U ? s /s +---+---+---+---+ B | B | U | ? | legend: +---+---+---+---+ B = Bounded U | U | U | ? | U = Unbounded +---+---+---+ ? = unknown boundedness ? | ? | s = signed (hence nonzero) +---+---+ /s = not signed """ result = True for arg in expr.args: _bounded = ask(Q.bounded(arg), assumptions) if _bounded: continue elif _bounded is None: if result is None: return None if ask(Q.nonzero(arg), assumptions) is None: return None if result is not False: result = None else: result = False return result
def MatMul(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if all(ask(Q.invertible(arg), assumptions) for arg in mmul.args): return True if any(ask(Q.invertible(arg), assumptions) is False for arg in mmul.args): return False
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 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
def refine_exp(expr, assumptions): """ Handler for exponential function. >>> from sympy import Symbol, Q, exp, I, pi >>> from sympy.assumptions.refine import refine_exp >>> from sympy.abc import x >>> refine_exp(exp(pi*I*2*x), Q.real(x)) >>> refine_exp(exp(pi*I*2*x), Q.integer(x)) 1 """ arg = expr.args[0] if arg.is_Mul: coeff = arg.as_coefficient(S.Pi*S.ImaginaryUnit) if coeff: if ask(Q.integer(2*coeff), assumptions): if ask(Q.even(coeff), assumptions): return S.One elif ask(Q.odd(coeff), assumptions): return S.NegativeOne elif ask(Q.even(coeff + S.Half), assumptions): return -S.ImaginaryUnit elif ask(Q.odd(coeff + S.Half), assumptions): return S.ImaginaryUnit
def Mul(expr, assumptions): """ Integer*Integer -> Integer Integer*Irrational -> !Integer Odd/Even -> !Integer Integer*Rational -> ? """ if expr.is_number: return AskIntegerHandler._number(expr, assumptions) _output = True for arg in expr.args: if not ask(Q.integer(arg), assumptions): if arg.is_Rational: if arg.q == 2: return ask(Q.even(2*expr), assumptions) if ~(arg.q & 1): return None elif ask(Q.irrational(arg), assumptions): if _output: _output = False else: return else: return else: return _output
def Basic(expr, assumptions): _real = ask(Q.real(expr), assumptions) if _real: _rational = ask(Q.rational(expr), assumptions) if _rational is None: return None return not _rational else: return _real
def MatPow(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if int_exp and ask(~Q.negative(exp), assumptions): return ask(Q.fullrank(base), assumptions) return None
def test_finally(): try: with assuming(Q.integer(x)): 1/0 except ZeroDivisionError: pass assert not ask(Q.integer(x))
def MatMul(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if (all(ask(Q.orthogonal(arg), assumptions) for arg in mmul.args) and factor == 1): return True if any(ask(Q.invertible(arg), assumptions) == False for arg in mmul.args): return False
def test_remove_safe(): global_assumptions.add(Q.integer(x)) with assuming(): assert ask(Q.integer(x)) global_assumptions.remove(Q.integer(x)) assert not ask(Q.integer(x)) assert ask(Q.integer(x)) global_assumptions.clear() # for the benefit of other tests
def Pow(expr, assumptions): """ Integer**Integer -> !Prime """ if expr.is_number: return AskPrimeHandler._number(expr, assumptions) if ask(Q.integer(expr.exp), assumptions) and ask(Q.integer(expr.base), assumptions): return False
def Symbol(expr, assumptions): """Objects are expected to be commutative unless otherwise stated""" assumps = conjuncts(assumptions) if Q.commutative(expr) in assumps: return True elif ~Q.commutative(expr) in assumps: return False return True
def log(expr, assumptions): r = ask(Q.real(expr.args[0]), assumptions) if r is not True: return r if ask(Q.positive(expr.args[0] - 1), assumptions): return True if ask(Q.negative(expr.args[0] - 1), assumptions): return False
def MatMul(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if (all(ask(Q.positive_definite(arg), assumptions) for arg in mmul.args) and factor > 0): return True if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T: return ask(Q.positive_definite( MatMul(*mmul.args[1:-1])), assumptions)
def test_custom_context(): """Test ask with custom assumptions context""" x = symbols('x') assert ask(Q.integer(x)) == None local_context = AssumptionsContext() local_context.add(Q.integer(x)) assert ask(Q.integer(x), context = local_context) == True assert ask(Q.integer(x)) == None
def MatMul(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if all(ask(Q.symmetric(arg), assumptions) for arg in mmul.args): return True if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T: if len(mmul.args) == 2: return True return ask(Q.symmetric(MatMul(*mmul.args[1:-1])), assumptions)
def test_global(): """Test ask with global assumptions""" x = symbols('x') assert ask(Q.integer(x)) == None global_assumptions.add(Q.integer(x)) assert ask(Q.integer(x)) == True global_assumptions.clear() assert ask(Q.integer(x)) == None
def Pow(expr, assumptions): """ Hermitian**Integer -> Hermitian """ if expr.is_number: return AskRealHandler._number(expr, assumptions) if ask(Q.hermitian(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): return True
def Pow(expr, assumptions): if expr.is_number: return expr.evalf() > 0 if ask(Q.positive(expr.base), assumptions): return True if ask(Q.negative(expr.base), assumptions): if ask(Q.even(expr.exp), assumptions): return True if ask(Q.even(expr.exp), assumptions): return False
def MatrixSlice(expr, assumptions): # TODO: implement sathandlers system for the matrices. # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). if ask(Q.diagonal(expr), assumptions): return True if not expr.on_diag: return None else: return ask(Q.symmetric(expr.parent), assumptions)
def MatrixSymbol(expr, assumptions): if not expr.is_square: return False # TODO: implement sathandlers system for the matrices. # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). if ask(Q.diagonal(expr), assumptions): return True if Q.symmetric(expr) in conjuncts(assumptions): return True
def MatPow(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None if exp.is_negative == False: return ask(Q.integer_elements(base), assumptions) return None
def Mul(expr, assumptions): if expr.is_number: return AskPositiveHandler._number(expr, assumptions) result = True for arg in expr.args: if ask(Q.positive(arg), assumptions): continue elif ask(Q.negative(arg), assumptions): result = result ^ True else: return return result
def Pow(expr, assumptions): if expr.is_number: return AskEvenHandler._number(expr, assumptions) if ask(Q.integer(expr.exp), assumptions): if ask(Q.positive(expr.exp), assumptions): return ask(Q.even(expr.base), assumptions) elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions): return False elif expr.base is S.NegativeOne: return False
def Basic(expr, assumptions): _positive = ask(Q.positive(expr), assumptions) if _positive: _integer = ask(Q.integer(expr), assumptions) if _integer: _prime = ask(Q.prime(expr), assumptions) if _prime is None: return return not _prime else: return _integer else: return _positive
def Mul(expr, assumptions): """ Return True if expr is bounded, False if not and None if unknown. Truth Table: +---+---+---+--------+ | | | | | | | B | U | ? | | | | | | +---+---+---+---+----+ | | | | | | | | | | s | /s | | | | | | | +---+---+---+---+----+ | | | | | | B | B | U | ? | | | | | | +---+---+---+---+----+ | | | | | | | U | | U | U | ? | | | | | | | +---+---+---+---+----+ | | | | | | ? | | | ? | | | | | | +---+---+---+---+----+ * B = Bounded * U = Unbounded * ? = unknown boundedness * s = signed (hence nonzero) * /s = not signed """ result = True for arg in expr.args: _bounded = ask(Q.bounded(arg), assumptions) if _bounded: continue elif _bounded is None: if result is None: return None if ask(Q.nonzero(arg), assumptions) is None: return None if result is not False: result = None else: result = False return result
def Pow(expr, assumptions): """ Rational ** Integer -> Rational Irrational ** Rational -> Irrational Rational ** Irrational -> ? """ if ask(Q.integer(expr.exp), assumptions): return ask(Q.rational(expr.base), assumptions) elif ask(Q.rational(expr.exp), assumptions): if ask(Q.prime(expr.base), assumptions): return False
def is_extended_nonnegative(obj, assumptions=None): if assumptions is None: return obj.is_extended_nonnegative return ask(Q.extended_nonnegative(obj), assumptions)
def MatrixSymbol(expr, assumptions): if not expr.is_square: return False if Q.invertible(expr) in conjuncts(assumptions): return True
def log(expr, assumptions): return ask(Q.finite(expr.args[0]), assumptions)
def Transpose(expr, assumptions): return ask(Q.orthogonal(expr.arg), assumptions)
def MatrixSlice(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.invertible(expr.parent), assumptions)
def MatrixSlice(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.positive_definite(expr.parent), assumptions)
def MatrixSymbol(expr, assumptions): if (not expr.is_square or ask(Q.invertible(expr), assumptions) is False): return False if Q.unitary(expr) in conjuncts(assumptions): return True
def Transpose(expr, assumptions): return ask(Q.lower_triangular(expr.arg), assumptions)
def MatrixSymbol(expr, assumptions): if Q.upper_triangular(expr) in conjuncts(assumptions): return True
def Inverse(expr, assumptions): return ask(Q.upper_triangular(expr.arg), assumptions)
def MatrixSlice(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.upper_triangular(expr.parent), assumptions)
def MatMul(expr, assumptions): factor, matrices = expr.as_coeff_matrices() if all(ask(Q.lower_triangular(m), assumptions) for m in matrices): return True
def is_extended_real(obj, assumptions=None): if assumptions is None: return obj.is_extended_real return ask(Q.extended_real(obj), assumptions)
def Transpose(expr, assumptions): return ask(Q.positive_definite(expr.arg), assumptions)
def Transpose(expr, assumptions): return ask(Q.unitary(expr.arg), assumptions)
def MatrixSymbol(expr, assumptions): if not expr.is_square: return False if Q.positive_definite(expr) in conjuncts(assumptions): return True
def MatrixSlice(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.orthogonal(expr.parent), assumptions)
def MatAdd(expr, assumptions): if all( ask(Q.positive_definite(arg), assumptions) for arg in expr.args): return True
def MatAdd(expr, assumptions): if (len(expr.args) == 1 and ask(Q.orthogonal(expr.args[0]), assumptions)): return True
def MatPow(expr, assumptions): # a power of a positive definite matrix is positive definite if ask(Q.positive_definite(expr.args[0]), assumptions): return True
def Transpose(expr, assumptions): return ask(Q.invertible(expr.arg), assumptions)
def MatrixSlice(expr, assumptions): if ask(Q.orthogonal(expr.parent), assumptions): return True
def Add(expr, assumptions): """ Return True if expr is bounded, False if not and None if unknown. Truth Table: +-------+-----+-----------+-----------+ | | | | | | | B | U | ? | | | | | | +-------+-----+---+---+---+---+---+---+ | | | | | | | | | | | |'+'|'-'|'x'|'+'|'-'|'x'| | | | | | | | | | +-------+-----+---+---+---+---+---+---+ | | | | | | B | B | U | ? | | | | | | +---+---+-----+---+---+---+---+---+---+ | | | | | | | | | | | |'+'| | U | ? | ? | U | ? | ? | | | | | | | | | | | | +---+-----+---+---+---+---+---+---+ | | | | | | | | | | | U |'-'| | ? | U | ? | ? | U | ? | | | | | | | | | | | | +---+-----+---+---+---+---+---+---+ | | | | | | | |'x'| | ? | ? | | | | | | | +---+---+-----+---+---+---+---+---+---+ | | | | | | ? | | | ? | | | | | | +-------+-----+-----------+---+---+---+ * 'B' = Bounded * 'U' = Unbounded * '?' = unknown boundedness * '+' = positive sign * '-' = negative sign * 'x' = sign unknown | * All Bounded -> True * 1 Unbounded and the rest Bounded -> False * >1 Unbounded, all with same known sign -> False * Any Unknown and unknown sign -> None * Else -> None When the signs are not the same you can have an undefined result as in oo - oo, hence 'bounded' is also undefined. """ sign = -1 # sign of unknown or infinite result = True for arg in expr.args: _bounded = ask(Q.finite(arg), assumptions) if _bounded: continue s = ask(Q.positive(arg), assumptions) # if there has been more than one sign or if the sign of this arg # is None and Bounded is None or there was already # an unknown sign, return None if sign != -1 and s != sign or \ s is None and (s == _bounded or s == sign): return None else: sign = s # once False, do not change if result is not False: result = _bounded return result
def Transpose(expr, assumptions): return ask(Q.fullrank(expr.arg), assumptions)
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
def MatMul(expr, assumptions): if all(ask(Q.fullrank(arg), assumptions) for arg in expr.args): return True
def test_assumptions(): rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) a, b = map(Symbol, 'ab') expr = a + b assert list(rl(expr, Q.integer(b))) == [b**a]
def MatrixSlice(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.unitary(expr.parent), assumptions)
def is_infinite(obj, assumptions=None): if assumptions is None: return obj.is_infinite return ask(Q.infinite(obj), assumptions)
def MatAdd(expr, assumptions): if all(ask(Q.lower_triangular(arg), assumptions) for arg in expr.args): return True