def test_bool_monomial(): x, y = symbols('x,y') assert bool_monomial(1, [x, y]) == y assert bool_monomial([1, 1], [x, y]) == And(x, y)
("lower_triangular", "matrices.AskLowerTriangularHandler"), ("diagonal", "matrices.AskDiagonalHandler"), ] for name, value in _handlers: register_handler(name, _val_template % value) known_facts_keys = [ getattr(Q, attr) for attr in Q.__dict__ if not attr.startswith('__') ] known_facts = And(Implies(Q.real, Q.complex), Implies(Q.real, Q.hermitian), Equivalent(Q.even, Q.integer & ~Q.odd), Equivalent(Q.extended_real, Q.real | Q.infinity), Equivalent(Q.odd, Q.integer & ~Q.even), Equivalent(Q.prime, Q.integer & Q.positive & ~Q.composite), Implies(Q.integer, Q.rational), Implies(Q.imaginary, Q.complex & ~Q.real), Implies(Q.imaginary, Q.antihermitian), Implies(Q.antihermitian, ~Q.hermitian), Equivalent(Q.negative, Q.nonzero & ~Q.positive), Equivalent(Q.positive, Q.nonzero & ~Q.negative), Equivalent(Q.rational, Q.real & ~Q.irrational), Equivalent(Q.real, Q.rational | Q.irrational), Implies(Q.nonzero, Q.real), Equivalent(Q.nonzero, Q.positive | Q.negative), Implies(Q.orthogonal, Q.positive_definite), Implies(Q.positive_definite, Q.invertible), Implies(Q.diagonal, Q.upper_triangular), Implies(Q.diagonal, Q.lower_triangular)) from sympy.assumptions.ask_generated import known_facts_dict, known_facts_cnf
def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, True)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes, sift, common_prefix # Given # P1 = Piecewise((e11, c1), (e12, c2), A) # P2 = Piecewise((e21, c1), (e22, c2), B) # ... # the folding of f(P1, P2) is trivially # Piecewise( # (f(e11, e21), c1), # (f(e12, e22), c2), # (f(Piecewise(A), Piecewise(B)), True)) # Certain objects end up rewriting themselves as thus, so # we do that grouping before the more generic folding. # The following applies this idea when f = Add or f = Mul # (and the expression is commutative). if expr.is_Add or expr.is_Mul and expr.is_commutative: p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True) pc = sift(p, lambda x: tuple([c for e, c in x.args])) for c in list(ordered(pc)): if len(pc[c]) > 1: pargs = [list(i.args) for i in pc[c]] # the first one is the same; there may be more com = common_prefix(*[[i.cond for i in j] for j in pargs]) n = len(com) collected = [] for i in range(n): collected.append( (expr.func(*[ai[i].expr for ai in pargs]), com[i])) remains = [] for a in pargs: if n == len(a): # no more args continue if a[n].cond == True: # no longer Piecewise remains.append(a[n].expr) else: # restore the remaining Piecewise remains.append(Piecewise(*a[n:], evaluate=False)) if remains: collected.append((expr.func(*remains), True)) args.append(Piecewise(*collected, evaluate=False)) continue args.extend(pc[c]) else: args = expr.args # fold folded = list(map(piecewise_fold, args)) for ec in cartes(*[(i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args)
def test_multivariate_bool_as_set(): x, y = symbols('x,y') assert And(x >= 0, y >= 0).as_set() == Interval(0, oo) * Interval(0, oo) assert Or(x >= 0, y >= 0).as_set() == S.Reals*S.Reals - \ Interval(-oo, 0, True, True)*Interval(-oo, 0, True, True)
def test_issue_8975(): assert Or(And(-oo < x, x <= -2), And(2 <= x, x < oo)).as_set() == \ Interval(-oo, -2) + Interval(2, oo)
def test_simplification(): """ Test working of simplification methods. """ set1 = [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]] set2 = [[0, 0, 0], [0, 1, 0], [1, 0, 1], [1, 1, 1]] assert SOPform([x, y, z], set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform([x, y, z], set2)) == \ Not(Or(And(Not(x), Not(z)), And(x, z))) assert POSform([x, y, z], set1 + set2) is true assert SOPform([x, y, z], set1 + set2) is true assert SOPform([Dummy(), Dummy(), Dummy()], set1 + set2) is true minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] assert (SOPform([w, x, y, z], minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, 3, 7, 11, 15] dontcares = [0, 2, 5] assert (SOPform([w, x, y, z], minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, [0, 0, 1, 1], 7, [1, 0, 1, 1], [1, 1, 1, 1]] dontcares = [0, [0, 0, 1, 0], 5] assert (SOPform([w, x, y, z], minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, {y: 1, z: 1}] dontcares = [0, [0, 0, 1, 0], 5] assert (SOPform([w, x, y, z], minterms, dontcares) == Or(And(Not(w), z), And(y, z))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [{y: 1, z: 1}, 1] dontcares = [[0, 0, 0, 0]] minterms = [[0, 0, 0]] raises(ValueError, lambda: SOPform([w, x, y, z], minterms)) raises(ValueError, lambda: POSform([w, x, y, z], minterms)) raises(TypeError, lambda: POSform([w, x, y, z], ["abcdefg"])) # test simplification ans = And(A, Or(B, C)) assert simplify_logic(A & (B | C)) == ans assert simplify_logic((A & B) | (A & C)) == ans assert simplify_logic(Implies(A, B)) == Or(Not(A), B) assert simplify_logic(Equivalent(A, B)) == \ Or(And(A, B), And(Not(A), Not(B))) assert simplify_logic(And(Equality(A, 2), C)) == And(Equality(A, 2), C) assert simplify_logic(And(Equality(A, 2), A)) is S.false assert simplify_logic(And(Equality(A, 2), A)) == And(Equality(A, 2), A) assert simplify_logic(And(Equality(A, B), C)) == And(Equality(A, B), C) assert simplify_logic(Or(And(Equality(A, 3), B), And(Equality(A, 3), C))) \ == And(Equality(A, 3), Or(B, C)) b = (~x & ~y & ~z) | (~x & ~y & z) e = And(A, b) assert simplify_logic(e) == A & ~x & ~y raises(ValueError, lambda: simplify_logic(A & (B | C), form='blabla')) # Check that expressions with nine variables or more are not simplified # (without the force-flag) a, b, c, d, e, f, g, h, j = symbols('a b c d e f g h j') expr = a & b & c & d & e & f & g & h & j | \ a & b & c & d & e & f & g & h & ~j # This expression can be simplified to get rid of the j variables assert simplify_logic(expr) == expr # check input ans = SOPform([x, y], [[1, 0]]) assert SOPform([x, y], [[1, 0]]) == ans assert POSform([x, y], [[1, 0]]) == ans raises(ValueError, lambda: SOPform([x], [[1]], [[1]])) assert SOPform([x], [[1]], [[0]]) is true assert SOPform([x], [[0]], [[1]]) is true assert SOPform([x], [], []) is false raises(ValueError, lambda: POSform([x], [[1]], [[1]])) assert POSform([x], [[1]], [[0]]) is true assert POSform([x], [[0]], [[1]]) is true assert POSform([x], [], []) is false # check working of simplify assert simplify((A & B) | (A & C)) == And(A, Or(B, C)) assert simplify(And(x, Not(x))) == False assert simplify(Or(x, Not(x))) == True assert simplify(And(Eq(x, 0), Eq(x, y))) == And(Eq(x, 0), Eq(y, 0)) assert And(Eq(x - 1, 0), Eq(x, y)).simplify() == And(Eq(x, 1), Eq(y, 1)) assert And(Ne(x - 1, 0), Ne(x, y)).simplify() == And(Ne(x, 1), Ne(x, y)) assert And(Eq(x - 1, 0), Ne(x, y)).simplify() == And(Eq(x, 1), Ne(y, 1)) assert And(Eq(x - 1, 0), Eq(x, z + y), Eq(y + x, 0)).simplify() == And(Eq(x, 1), Eq(y, -1), Eq(z, 2)) assert And(Eq(x - 1, 0), Eq(x + 2, 3)).simplify() == Eq(x, 1) assert And(Ne(x - 1, 0), Ne(x + 2, 3)).simplify() == Ne(x, 1) assert And(Eq(x - 1, 0), Eq(x + 2, 2)).simplify() == False assert And(Ne(x - 1, 0), Ne(x + 2, 2)).simplify() == And(Ne(x, 1), Ne(x, 0))
def test_distribute(): assert distribute_and_over_or(Or(And(A, B), C)) == And(Or(A, C), Or(B, C)) assert distribute_or_over_and(And(A, Or(B, C))) == Or(And(A, B), And(A, C))
def _eval_interval(self, sym, a, b): """Evaluates the function along the sym in a given interval ab""" # FIXME: Currently complex intervals are not supported. A possible # replacement algorithm, discussed in issue 2128, can be found in the # following papers; # http://portal.acm.org/citation.cfm?id=281649 # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf if a is None or b is None: # In this case, it is just simple substitution return piecewise_fold( super(Piecewise, self)._eval_interval(sym, a, b)) mul = 1 if (a == b) is True: return S.Zero elif (a > b) is True: a, b, mul = b, a, -1 elif (a <= b) is not True: newargs = [] for e, c in self.args: intervals = self._sort_expr_cond( sym, S.NegativeInfinity, S.Infinity, c) values = [] for lower, upper, expr in intervals: if (a < lower) is True: mid = lower rep = b val = e._eval_interval(sym, mid, b) val += self._eval_interval(sym, a, mid) elif (a > upper) is True: mid = upper rep = b val = e._eval_interval(sym, mid, b) val += self._eval_interval(sym, a, mid) elif (a >= lower) is True and (a <= upper) is True: rep = b val = e._eval_interval(sym, a, b) elif (b < lower) is True: mid = lower rep = a val = e._eval_interval(sym, a, mid) val += self._eval_interval(sym, mid, b) elif (b > upper) is True: mid = upper rep = a val = e._eval_interval(sym, a, mid) val += self._eval_interval(sym, mid, b) elif ((b >= lower) is True) and ((b <= upper) is True): rep = a val = e._eval_interval(sym, a, b) else: raise NotImplementedError( """The evaluation of a Piecewise interval when both the lower and the upper limit are symbolic is not yet implemented.""") values.append(val) if len(set(values)) == 1: try: c = c.subs(sym, rep) except AttributeError: pass e = values[0] newargs.append((e, c)) else: for i in range(len(values)): newargs.append((values[i], (c == True and i == len(values) - 1) or And(rep >= intervals[i][0], rep <= intervals[i][1]))) return self.func(*newargs) # Determine what intervals the expr,cond pairs affect. int_expr = self._sort_expr_cond(sym, a, b) # Finally run through the intervals and sum the evaluation. ret_fun = 0 for int_a, int_b, expr in int_expr: if isinstance(expr, Piecewise): # If we still have a Piecewise by now, _sort_expr_cond would # already have determined that its conditions are independent # of the integration variable, thus we just use substitution. ret_fun += piecewise_fold( super(Piecewise, expr)._eval_interval(sym, Max(a, int_a), Min(b, int_b))) else: ret_fun += expr._eval_interval(sym, Max(a, int_a), Min(b, int_b)) return mul * ret_fun
known_facts = And( Implies(Q.real, Q.complex), Implies(Q.real, Q.hermitian), Equivalent(Q.even, Q.integer & ~Q.odd), Equivalent(Q.extended_real, Q.real | Q.infinity), Equivalent(Q.odd, Q.integer & ~Q.even), Equivalent(Q.prime, Q.integer & Q.positive & ~Q.composite), Implies(Q.integer, Q.rational), Implies(Q.rational, Q.algebraic), Implies(Q.algebraic, Q.complex), Implies(Q.imaginary, Q.complex & ~Q.real), Implies(Q.imaginary, Q.antihermitian), Implies(Q.antihermitian, ~Q.hermitian), Equivalent(Q.negative, Q.nonzero & ~Q.positive), Equivalent(Q.positive, Q.nonzero & ~Q.negative), Equivalent(Q.rational, Q.real & ~Q.irrational), Equivalent(Q.real, Q.rational | Q.irrational), Implies(Q.nonzero, Q.real), Equivalent(Q.nonzero, Q.positive | Q.negative), Implies(Q.orthogonal, Q.positive_definite), Implies(Q.orthogonal, Q.unitary), Implies(Q.unitary & Q.real, Q.orthogonal), Implies(Q.unitary, Q.normal), Implies(Q.unitary, Q.invertible), Implies(Q.normal, Q.square), Implies(Q.diagonal, Q.normal), Implies(Q.positive_definite, Q.invertible), Implies(Q.diagonal, Q.upper_triangular), Implies(Q.diagonal, Q.lower_triangular), Implies(Q.lower_triangular, Q.triangular), Implies(Q.upper_triangular, Q.triangular), Implies(Q.triangular, Q.upper_triangular | Q.lower_triangular), Implies(Q.upper_triangular & Q.lower_triangular, Q.diagonal), Implies(Q.diagonal, Q.symmetric), Implies(Q.unit_triangular, Q.triangular), Implies(Q.invertible, Q.fullrank), Implies(Q.invertible, Q.square), Implies(Q.symmetric, Q.square), Implies(Q.fullrank & Q.square, Q.invertible), Equivalent(Q.invertible, ~Q.singular), )
def get_known_facts(x=None): """ Facts between unary predicates. Parameters ========== x : Symbol, optional Placeholder symbol for unary facts. Default is ``Symbol('x')``. Returns ======= fact : Known facts in conjugated normal form. """ if x is None: x = Symbol('x') fact = And( # primitive predicates for extended real exclude each other. Exclusive(Q.negative_infinite(x), Q.negative(x), Q.zero(x), Q.positive(x), Q.positive_infinite(x)), # build complex plane Exclusive(Q.real(x), Q.imaginary(x)), Implies(Q.real(x) | Q.imaginary(x), Q.complex(x)), # other subsets of complex Exclusive(Q.transcendental(x), Q.algebraic(x)), Equivalent(Q.real(x), Q.rational(x) | Q.irrational(x)), Exclusive(Q.irrational(x), Q.rational(x)), Implies(Q.rational(x), Q.algebraic(x)), # integers Exclusive(Q.even(x), Q.odd(x)), Implies(Q.integer(x), Q.rational(x)), Implies(Q.zero(x), Q.even(x)), Exclusive(Q.composite(x), Q.prime(x)), Implies(Q.composite(x) | Q.prime(x), Q.integer(x) & Q.positive(x)), Implies(Q.even(x) & Q.positive(x) & ~Q.prime(x), Q.composite(x)), # hermitian and antihermitian Implies(Q.real(x), Q.hermitian(x)), Implies(Q.imaginary(x), Q.antihermitian(x)), Implies(Q.zero(x), Q.hermitian(x) | Q.antihermitian(x)), # define finity and infinity, and build extended real line Exclusive(Q.infinite(x), Q.finite(x)), Implies(Q.complex(x), Q.finite(x)), Implies( Q.negative_infinite(x) | Q.positive_infinite(x), Q.infinite(x)), # commutativity Implies(Q.finite(x) | Q.infinite(x), Q.commutative(x)), # matrices Implies(Q.orthogonal(x), Q.positive_definite(x)), Implies(Q.orthogonal(x), Q.unitary(x)), Implies(Q.unitary(x) & Q.real_elements(x), Q.orthogonal(x)), Implies(Q.unitary(x), Q.normal(x)), Implies(Q.unitary(x), Q.invertible(x)), Implies(Q.normal(x), Q.square(x)), Implies(Q.diagonal(x), Q.normal(x)), Implies(Q.positive_definite(x), Q.invertible(x)), Implies(Q.diagonal(x), Q.upper_triangular(x)), Implies(Q.diagonal(x), Q.lower_triangular(x)), Implies(Q.lower_triangular(x), Q.triangular(x)), Implies(Q.upper_triangular(x), Q.triangular(x)), Implies(Q.triangular(x), Q.upper_triangular(x) | Q.lower_triangular(x)), Implies(Q.upper_triangular(x) & Q.lower_triangular(x), Q.diagonal(x)), Implies(Q.diagonal(x), Q.symmetric(x)), Implies(Q.unit_triangular(x), Q.triangular(x)), Implies(Q.invertible(x), Q.fullrank(x)), Implies(Q.invertible(x), Q.square(x)), Implies(Q.symmetric(x), Q.square(x)), Implies(Q.fullrank(x) & Q.square(x), Q.invertible(x)), Equivalent(Q.invertible(x), ~Q.singular(x)), Implies(Q.integer_elements(x), Q.real_elements(x)), Implies(Q.real_elements(x), Q.complex_elements(x)), ) return fact
from sympy.logic.boolalg import And old_sum = Sum(f, (i, a, b)) if b != S.Infinity: if a == S.NegativeInfinity: res = _eval_sum_hyper(f.subs(i, -i), i, -b) if res is not None: return Piecewise(res, (old_sum, True)) else: res1 = _eval_sum_hyper(f, i, a) res2 = _eval_sum_hyper(f, i, b + 1) if res1 is None or res2 is None: return None (res1, cond1), (res2, cond2) = res1, res2 cond = And(cond1, cond2) if cond is False: return None return Piecewise((res1 - res2, cond), (old_sum, True)) if a == S.NegativeInfinity: res1 = _eval_sum_hyper(f.subs(i, -i), i, 1) res2 = _eval_sum_hyper(f, i, 0) if res1 is None or res2 is None: return None res1, cond1 = res1 res2, cond2 = res2 cond = And(cond1, cond2) if cond is False: return None return Piecewise((res1 + res2, cond), (old_sum, True))
def test_And(): assert And() is true assert And(A) == A assert And(True) is true assert And(False) is false assert And(True, True) is true assert And(True, False) is false assert And(False, False) is false assert And(True, A) == A assert And(False, A) is false assert And(True, True, True) is true assert And(True, True, A) == A assert And(True, False, A) is false assert And(1, A) == A raises(TypeError, lambda: And(2, A)) raises(TypeError, lambda: And(A < 2, A)) assert And(A < 1, A >= 1) is false e = A > 1 assert And(e, e.canonical) == e.canonical g, l, ge, le = A > B, B < A, A >= B, B <= A assert And(g, l, ge, le) == And(ge, g) assert {And(*i) for i in permutations((l, g, le, ge))} == {And(ge, g)} assert And(And(Eq(a, 0), Eq(b, 0)), And(Ne(a, 0), Eq(c, 0))) is false
def test_to_anf(): x, y, z = symbols('x,y,z') assert to_anf(And(x, y)) == And(x, y) assert to_anf(Or(x, y)) == Xor(x, y, And(x, y)) assert to_anf(Or(Implies(x, y), And(x, y), y)) == \ Xor(x, True, x & y, remove_true=False) assert to_anf(Or(Nand(x, y), Nor(x, y), Xnor(x, y), Implies(x, y))) == True assert to_anf(Or(x, Not(y), Nor(x,z), And(x, y), Nand(y, z))) == \ Xor(True, And(y, z), And(x, y, z), remove_true=False) assert to_anf(Xor(x, y)) == Xor(x, y) assert to_anf(Not(x)) == Xor(x, True, remove_true=False) assert to_anf(Nand(x, y)) == Xor(True, And(x, y), remove_true=False) assert to_anf(Nor(x, y)) == Xor(x, y, True, And(x, y), remove_true=False) assert to_anf(Implies(x, y)) == Xor(x, True, And(x, y), remove_true=False) assert to_anf(Equivalent(x, y)) == Xor(x, y, True, remove_true=False) assert to_anf(Nand(x | y, x >> y), deep=False) == \ Xor(True, And(Or(x, y), Implies(x, y)), remove_true=False) assert to_anf(Nor(x ^ y, x & y), deep=False) == \ Xor(True, Or(Xor(x, y), And(x, y)), remove_true=False)
def test_convert_to_varsSOP(): assert _convert_to_varsSOP([0, 1, 0], [x, y, z]) == And(Not(x), y, Not(z)) assert _convert_to_varsSOP([3, 1, 0], [x, y, z]) == And(y, Not(z))
def test_fcode_Xlogical(): x, y, z = symbols("x y z") # binary Xor assert fcode(Xor(x, y, evaluate=False), source_format="free") == \ "x .neqv. y" assert fcode(Xor(x, Not(y), evaluate=False), source_format="free") == \ "x .neqv. .not. y" assert fcode(Xor(Not(x), y, evaluate=False), source_format="free") == \ "y .neqv. .not. x" assert fcode(Xor(Not(x), Not(y), evaluate=False), source_format="free") == ".not. x .neqv. .not. y" assert fcode(Not(Xor(x, y, evaluate=False), evaluate=False), source_format="free") == ".not. (x .neqv. y)" # binary Equivalent assert fcode(Equivalent(x, y), source_format="free") == "x .eqv. y" assert fcode(Equivalent(x, Not(y)), source_format="free") == \ "x .eqv. .not. y" assert fcode(Equivalent(Not(x), y), source_format="free") == \ "y .eqv. .not. x" assert fcode(Equivalent(Not(x), Not(y)), source_format="free") == \ ".not. x .eqv. .not. y" assert fcode(Not(Equivalent(x, y), evaluate=False), source_format="free") == ".not. (x .eqv. y)" # mixed And/Equivalent assert fcode(Equivalent(And(y, z), x), source_format="free") == \ "x .eqv. y .and. z" assert fcode(Equivalent(And(z, x), y), source_format="free") == \ "y .eqv. x .and. z" assert fcode(Equivalent(And(x, y), z), source_format="free") == \ "z .eqv. x .and. y" assert fcode(And(Equivalent(y, z), x), source_format="free") == \ "x .and. (y .eqv. z)" assert fcode(And(Equivalent(z, x), y), source_format="free") == \ "y .and. (x .eqv. z)" assert fcode(And(Equivalent(x, y), z), source_format="free") == \ "z .and. (x .eqv. y)" # mixed Or/Equivalent assert fcode(Equivalent(Or(y, z), x), source_format="free") == \ "x .eqv. y .or. z" assert fcode(Equivalent(Or(z, x), y), source_format="free") == \ "y .eqv. x .or. z" assert fcode(Equivalent(Or(x, y), z), source_format="free") == \ "z .eqv. x .or. y" assert fcode(Or(Equivalent(y, z), x), source_format="free") == \ "x .or. (y .eqv. z)" assert fcode(Or(Equivalent(z, x), y), source_format="free") == \ "y .or. (x .eqv. z)" assert fcode(Or(Equivalent(x, y), z), source_format="free") == \ "z .or. (x .eqv. y)" # mixed Xor/Equivalent assert fcode(Equivalent(Xor(y, z, evaluate=False), x), source_format="free") == "x .eqv. (y .neqv. z)" assert fcode(Equivalent(Xor(z, x, evaluate=False), y), source_format="free") == "y .eqv. (x .neqv. z)" assert fcode(Equivalent(Xor(x, y, evaluate=False), z), source_format="free") == "z .eqv. (x .neqv. y)" assert fcode(Xor(Equivalent(y, z), x, evaluate=False), source_format="free") == "x .neqv. (y .eqv. z)" assert fcode(Xor(Equivalent(z, x), y, evaluate=False), source_format="free") == "y .neqv. (x .eqv. z)" assert fcode(Xor(Equivalent(x, y), z, evaluate=False), source_format="free") == "z .neqv. (x .eqv. y)" # mixed And/Xor assert fcode(Xor(And(y, z), x, evaluate=False), source_format="free") == \ "x .neqv. y .and. z" assert fcode(Xor(And(z, x), y, evaluate=False), source_format="free") == \ "y .neqv. x .and. z" assert fcode(Xor(And(x, y), z, evaluate=False), source_format="free") == \ "z .neqv. x .and. y" assert fcode(And(Xor(y, z, evaluate=False), x), source_format="free") == \ "x .and. (y .neqv. z)" assert fcode(And(Xor(z, x, evaluate=False), y), source_format="free") == \ "y .and. (x .neqv. z)" assert fcode(And(Xor(x, y, evaluate=False), z), source_format="free") == \ "z .and. (x .neqv. y)" # mixed Or/Xor assert fcode(Xor(Or(y, z), x, evaluate=False), source_format="free") == \ "x .neqv. y .or. z" assert fcode(Xor(Or(z, x), y, evaluate=False), source_format="free") == \ "y .neqv. x .or. z" assert fcode(Xor(Or(x, y), z, evaluate=False), source_format="free") == \ "z .neqv. x .or. y" assert fcode(Or(Xor(y, z, evaluate=False), x), source_format="free") == \ "x .or. (y .neqv. z)" assert fcode(Or(Xor(z, x, evaluate=False), y), source_format="free") == \ "y .or. (x .neqv. z)" assert fcode(Or(Xor(x, y, evaluate=False), z), source_format="free") == \ "z .or. (x .neqv. y)" # trinary Xor assert fcode(Xor(x, y, z, evaluate=False), source_format="free") == \ "x .neqv. y .neqv. z" assert fcode(Xor(x, y, Not(z), evaluate=False), source_format="free") == \ "x .neqv. y .neqv. .not. z" assert fcode(Xor(x, Not(y), z, evaluate=False), source_format="free") == \ "x .neqv. z .neqv. .not. y" assert fcode(Xor(Not(x), y, z, evaluate=False), source_format="free") == \ "y .neqv. z .neqv. .not. x"
known_facts_cnf = And( Or(Q.invertible, Q.singular), Or(Not(Q.rational), Q.algebraic), Or(Not(Q.imaginary), Q.antihermitian), Or(Not(Q.algebraic), Q.complex), Or(Not(Q.imaginary), Q.complex), Or(Not(Q.real), Q.complex), Or(Not(Q.real_elements), Q.complex_elements), Or(Not(Q.infinity), Q.extended_real), Or(Not(Q.real), Q.extended_real), Or(Not(Q.invertible), Q.fullrank), Or(Not(Q.real), Q.hermitian), Or(Not(Q.even), Q.integer), Or(Not(Q.odd), Q.integer), Or(Not(Q.prime), Q.integer), Or(Not(Q.positive_definite), Q.invertible), Or(Not(Q.unitary), Q.invertible), Or(Not(Q.diagonal), Q.lower_triangular), Or(Not(Q.negative), Q.nonzero), Or(Not(Q.positive), Q.nonzero), Or(Not(Q.diagonal), Q.normal), Or(Not(Q.unitary), Q.normal), Or(Not(Q.prime), Q.positive), Or(Not(Q.orthogonal), Q.positive_definite), Or(Not(Q.integer), Q.rational), Or(Not(Q.irrational), Q.real), Or(Not(Q.nonzero), Q.real), Or(Not(Q.rational), Q.real), Or(Not(Q.integer_elements), Q.real_elements), Or(Not(Q.invertible), Q.square), Or(Not(Q.normal), Q.square), Or(Not(Q.symmetric), Q.square), Or(Not(Q.diagonal), Q.symmetric), Or(Not(Q.lower_triangular), Q.triangular), Or(Not(Q.unit_triangular), Q.triangular), Or(Not(Q.upper_triangular), Q.triangular), Or(Not(Q.orthogonal), Q.unitary), Or(Not(Q.diagonal), Q.upper_triangular), Or(Not(Q.antihermitian), Not(Q.hermitian)), Or(Not(Q.composite), Not(Q.prime)), Or(Not(Q.even), Not(Q.odd)), Or(Not(Q.imaginary), Not(Q.real)), Or(Not(Q.invertible), Not(Q.singular)), Or(Not(Q.irrational), Not(Q.rational)), Or(Not(Q.negative), Not(Q.positive)), Or(Not(Q.integer), Q.even, Q.odd), Or(Not(Q.extended_real), Q.infinity, Q.real), Or(Not(Q.real), Q.irrational, Q.rational), Or(Not(Q.triangular), Q.lower_triangular, Q.upper_triangular), Or(Not(Q.nonzero), Q.negative, Q.positive), Or(Not(Q.lower_triangular), Not(Q.upper_triangular), Q.diagonal), Or(Not(Q.fullrank), Not(Q.square), Q.invertible), Or(Not(Q.real), Not(Q.unitary), Q.orthogonal), Or(Not(Q.integer), Not(Q.positive), Q.composite, Q.prime))
def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3, degree_offset=0, unnecessary_permutations=None): """ A wrapper around the heurisch integration algorithm. This method takes the result from heurisch and checks for poles in the denominator. For each of these poles, the integral is reevaluated, and the final integration result is given in terms of a Piecewise. Examples ======== >>> from sympy.core import symbols >>> from sympy.functions import cos >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper >>> n, x = symbols('n x') >>> heurisch(cos(n*x), x) sin(n*x)/n >>> heurisch_wrapper(cos(n*x), x) Piecewise((x, n == 0), (sin(n*x)/n, True)) See Also ======== heurisch """ f = sympify(f) if x not in f.free_symbols: return f * x res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations) if not isinstance(res, Basic): return res # We consider each denominator in the expression, and try to find # cases where one or more symbolic denominator might be zero. The # conditions for these cases are stored in the list slns. slns = [] for d in denoms(res): try: slns += solve(d, dict=True, exclude=(x, )) except NotImplementedError: pass if not slns: return res slns = list(uniq(slns)) # Remove the solutions corresponding to poles in the original expression. slns0 = [] for d in denoms(f): try: slns0 += solve(d, dict=True, exclude=(x, )) except NotImplementedError: pass slns = [s for s in slns if s not in slns0] if not slns: return res if len(slns) > 1: eqs = [] for sub_dict in slns: eqs.extend([Eq(key, value) for key, value in sub_dict.items()]) slns = solve(eqs, dict=True, exclude=(x, )) + slns # For each case listed in the list slns, we reevaluate the integral. pairs = [] for sub_dict in slns: expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations) cond = And(*[Eq(key, value) for key, value in sub_dict.items()]) pairs.append((expr, cond)) pairs.append((heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations), True)) return Piecewise(*pairs)
def as_relational(self, symbol): """Rewrite an Intersection in terms of equalities and logic operators""" return And(*[set.as_relational(symbol) for set in self.args])
def test_And(): assert And() is true assert And(A) == A assert And(True) is true assert And(False) is false assert And(True, True) is true assert And(True, False) is false assert And(False, False) is false assert And(True, A) == A assert And(False, A) is false assert And(True, True, True) is true assert And(True, True, A) == A assert And(True, False, A) is false assert And(1, A) == A raises(TypeError, lambda: And(2, A)) raises(TypeError, lambda: And(A < 2, A)) assert And(A < 1, A >= 1) is false e = A > 1 assert And(e, e.canonical) == e.canonical g, l, ge, le = A > B, B < A, A >= B, B <= A assert And(g, l, ge, le) == And(l, le)
def _contains(self, other): from sympy.logic.boolalg import And return And(*[set.contains(other) for set in self.args])
def test_true_false(): assert true is S.true assert false is S.false assert true is not True assert false is not False assert true assert not false assert true == True assert false == False assert not (true == False) assert not (false == True) assert not (true == false) assert hash(true) == hash(True) assert hash(false) == hash(False) assert len({true, True}) == len({false, False}) == 1 assert isinstance(true, BooleanAtom) assert isinstance(false, BooleanAtom) # We don't want to subclass from bool, because bool subclasses from # int. But operators like &, |, ^, <<, >>, and ~ act differently on 0 and # 1 then we want them to on true and false. See the docstrings of the # various And, Or, etc. functions for examples. assert not isinstance(true, bool) assert not isinstance(false, bool) # Note: using 'is' comparison is important here. We want these to return # true and false, not True and False assert Not(true) is false assert Not(True) is false assert Not(false) is true assert Not(False) is true assert ~true is false assert ~false is true for T, F in cartes([True, true], [False, false]): assert And(T, F) is false assert And(F, T) is false assert And(F, F) is false assert And(T, T) is true assert And(T, x) == x assert And(F, x) is false if not (T is True and F is False): assert T & F is false assert F & T is false if F is not False: assert F & F is false if T is not True: assert T & T is true assert Or(T, F) is true assert Or(F, T) is true assert Or(F, F) is false assert Or(T, T) is true assert Or(T, x) is true assert Or(F, x) == x if not (T is True and F is False): assert T | F is true assert F | T is true if F is not False: assert F | F is false if T is not True: assert T | T is true assert Xor(T, F) is true assert Xor(F, T) is true assert Xor(F, F) is false assert Xor(T, T) is false assert Xor(T, x) == ~x assert Xor(F, x) == x if not (T is True and F is False): assert T ^ F is true assert F ^ T is true if F is not False: assert F ^ F is false if T is not True: assert T ^ T is false assert Nand(T, F) is true assert Nand(F, T) is true assert Nand(F, F) is true assert Nand(T, T) is false assert Nand(T, x) == ~x assert Nand(F, x) is true assert Nor(T, F) is false assert Nor(F, T) is false assert Nor(F, F) is true assert Nor(T, T) is false assert Nor(T, x) is false assert Nor(F, x) == ~x assert Implies(T, F) is false assert Implies(F, T) is true assert Implies(F, F) is true assert Implies(T, T) is true assert Implies(T, x) == x assert Implies(F, x) is true assert Implies(x, T) is true assert Implies(x, F) == ~x if not (T is True and F is False): assert T >> F is false assert F << T is false assert F >> T is true assert T << F is true if F is not False: assert F >> F is true assert F << F is true if T is not True: assert T >> T is true assert T << T is true assert Equivalent(T, F) is false assert Equivalent(F, T) is false assert Equivalent(F, F) is true assert Equivalent(T, T) is true assert Equivalent(T, x) == x assert Equivalent(F, x) == ~x assert Equivalent(x, T) == x assert Equivalent(x, F) == ~x assert ITE(T, T, T) is true assert ITE(T, T, F) is true assert ITE(T, F, T) is false assert ITE(T, F, F) is false assert ITE(F, T, T) is true assert ITE(F, T, F) is false assert ITE(F, F, T) is true assert ITE(F, F, F) is false assert all(i.simplify(1, 2) is i for i in (S.true, S.false))
def as_relational(self, x): from sympy.functions.elementary.integers import floor return And(Eq(floor(x), x), -oo < x, x < oo)
def test_issue_8777(): assert And(x > 2, x < oo).as_set() == Interval(2, oo, left_open=True) assert And(x >= 1, x < oo).as_set() == Interval(1, oo) assert (x < oo).as_set() == Interval(-oo, oo) assert (x > -oo).as_set() == Interval(-oo, oo)
def _handle_irel(self, x, handler): """Return either None (if the conditions of self depend only on x) else a Piecewise expression whose expressions (handled by the handler that was passed) are paired with the governing x-independent relationals, e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) -> Piecewise( (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)), (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)), (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)), (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True)) """ # identify governing relationals rel = self.atoms(Relational) irel = list( ordered([ r for r in rel if x not in r.free_symbols and r not in (S.true, S.false) ])) if irel: args = {} exprinorder = [] for truth in product((1, 0), repeat=len(irel)): reps = dict(zip(irel, truth)) # only store the true conditions since the false are implied # when they appear lower in the Piecewise args if 1 not in truth: cond = None # flag this one so it doesn't get combined else: andargs = Tuple(*[i for i in reps if reps[i]]) free = list(andargs.free_symbols) if len(free) == 1: from sympy.solvers.inequalities import ( reduce_inequalities, _solve_inequality) try: t = reduce_inequalities(andargs, free[0]) # ValueError when there are potentially # nonvanishing imaginary parts except (ValueError, NotImplementedError): # at least isolate free symbol on left t = And(*[ _solve_inequality(a, free[0], linear=True) for a in andargs ]) else: t = And(*andargs) if t is S.false: continue # an impossible combination cond = t expr = handler(self.xreplace(reps)) if isinstance(expr, self.func) and len(expr.args) == 1: expr, econd = expr.args[0] cond = And(econd, True if cond is None else cond) # the ec pairs are being collected since all possibilities # are being enumerated, but don't put the last one in since # its expr might match a previous expression and it # must appear last in the args if cond is not None: args.setdefault(expr, []).append(cond) # but since we only store the true conditions we must maintain # the order so that the expression with the most true values # comes first exprinorder.append(expr) # convert collected conditions as args of Or for k in args: args[k] = Or(*args[k]) # take them in the order obtained args = [(e, args[e]) for e in uniq(exprinorder)] # add in the last arg args.append((expr, True)) # if any condition reduced to True, it needs to go last # and there should only be one of them or else the exprs # should agree trues = [i for i in range(len(args)) if args[i][1] is S.true] if not trues: # make the last one True since all cases were enumerated e, c = args[-1] args[-1] = (e, S.true) else: assert len(set([e for e, c in [args[i] for i in trues]])) == 1 args.append(args.pop(trues.pop())) while trues: args.pop(trues.pop()) return Piecewise(*args)
def test_BooleanFunction_diff(): assert And(x, y).diff(x) == Piecewise((0, Eq(y, False)), (1, True))
def test_DiscreteMarkovChain(): # pass only the name X = DiscreteMarkovChain("X") assert isinstance(X.state_space, Range) assert X.index_set == S.Naturals0 assert isinstance(X.transition_probabilities, MatrixSymbol) t = symbols('t', positive=True, integer=True) assert isinstance(X[t], RandomIndexedSymbol) assert E(X[0]) == Expectation(X[0]) raises(TypeError, lambda: DiscreteMarkovChain(1)) raises(NotImplementedError, lambda: X(t)) raises(NotImplementedError, lambda: X.communication_classes()) raises(NotImplementedError, lambda: X.canonical_form()) raises(NotImplementedError, lambda: X.decompose()) nz = Symbol('n', integer=True) TZ = MatrixSymbol('M', nz, nz) SZ = Range(nz) YZ = DiscreteMarkovChain('Y', SZ, TZ) assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1] raises(ValueError, lambda: sample_stochastic_process(t)) raises(ValueError, lambda: next(sample_stochastic_process(X))) # pass name and state_space # any hashable object should be a valid state # states should be valid as a tuple/set/list/Tuple/Range sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True) state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain("Y", (1, 2, 3))], Tuple(S(1), exp(sym), Str('World'), sympify=False), Range(-1, 5, 2), [rainy, cloudy, sunny]] chains = [ DiscreteMarkovChain("Y", state_space) for state_space in state_spaces ] for i, Y in enumerate(chains): assert isinstance(Y.transition_probabilities, MatrixSymbol) assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet( *state_spaces[i]) assert Y.number_of_states == 3 with ignore_warnings( UserWarning): # TODO: Restore tests once warnings are removed assert P(Eq(Y[2], 1), Eq(Y[0], 2), evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2)) assert E(Y[0]) == Expectation(Y[0]) raises(ValueError, lambda: next(sample_stochastic_process(Y))) raises(TypeError, lambda: DiscreteMarkovChain("Y", dict((1, 1)))) Y = DiscreteMarkovChain("Y", Range(1, t, 2)) assert Y.number_of_states == ceiling((t - 1) / 2) # pass name and transition_probabilities chains = [ DiscreteMarkovChain("Y", trans_probs=Matrix([[]])), DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])), DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1 - pi], [sym, 1 - sym]])) ] for Z in chains: assert Z.number_of_states == Z.transition_probabilities.shape[0] assert isinstance(Z.transition_probabilities, ImmutableMatrix) # pass name, state_space and transition_probabilities T = Matrix([[0.5, 0.2, 0.3], [0.2, 0.5, 0.3], [0.2, 0.3, 0.5]]) TS = MatrixSymbol('T', 3, 3) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS) assert Y.joint_distribution(1, Y[2], 3) == JointDistribution(Y[1], Y[2], Y[3]) raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol)) assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2) assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) - (TS[0, 2] * TS[1, 0] + TS[1, 1] * TS[1, 2] + TS[1, 2] * TS[2, 2])).simplify() == 0 assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1)) assert P(Eq(YS[3], 3), Eq( YS[1], 1)) == TS[0, 2] * TS[1, 0] + TS[1, 1] * TS[1, 2] + TS[1, 2] * TS[2, 2] TO = Matrix([[0.25, 0.75, 0], [0, 0.25, 0.75], [0.75, 0, 0.25]]) assert P(Eq(Y[3], 2), Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float( 0.375, 3) with ignore_warnings( UserWarning): ### TODO: Restore tests once warnings are removed assert E(Y[3], evaluate=False) == Expectation(Y[3]) assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3) TSO = MatrixSymbol('T', 4, 4) raises( ValueError, lambda: str(P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO)))) raises(TypeError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M'))) raises( ValueError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4))) raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6))) raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1))) # extended tests for probability queries TO1 = Matrix([[Rational(1, 4), Rational(3, 4), 0], [Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]]) assert P( And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Probability(Eq(Y[0], 0)), Rational(1, 4)) & TransitionMatrixOf(Y, TO1)) == Rational(1, 16) assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \ Probability(Eq(Y[0], 0))/4 assert P( Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) assert P( Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) assert P( Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) is S.Zero assert P( Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) is S.Zero assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Y[1], 1)) == 0.1 * Probability(Eq(Y[0], 0)) # testing properties of Markov chain TO2 = Matrix([[S.One, 0, 0], [Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]]) TO3 = Matrix([[Rational(1, 4), Rational(3, 4), 0], [Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]]) Y2 = DiscreteMarkovChain('Y', trans_probs=TO2) Y3 = DiscreteMarkovChain('Y', trans_probs=TO3) assert Y3.fundamental_matrix() == ImmutableMatrix( [[176, 81, -132], [36, 141, -52], [-44, -39, 208]]) / 125 assert Y2.is_absorbing_chain() == True assert Y3.is_absorbing_chain() == False assert Y2.canonical_form() == ([0, 1, 2], TO2) assert Y3.canonical_form() == ([0, 1, 2], TO3) assert Y2.decompose() == ([0, 1, 2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3, []), Matrix(0, 0, [])) TO4 = Matrix([[Rational(1, 5), Rational(2, 5), Rational(2, 5)], [Rational(1, 10), S.Half, Rational(2, 5)], [Rational(3, 5), Rational(3, 10), Rational(1, 10)]]) Y4 = DiscreteMarkovChain('Y', trans_probs=TO4) w = ImmutableMatrix([[Rational(11, 39), Rational(16, 39), Rational(4, 13)]]) assert Y4.limiting_distribution == w assert Y4.is_regular() == True assert Y4.is_ergodic() == True TS1 = MatrixSymbol('T', 3, 3) Y5 = DiscreteMarkovChain('Y', trans_probs=TS1) assert Y5.limiting_distribution(w, TO4).doit() == True assert Y5.stationary_distribution(condition_set=True).subs( TS1, TO4).contains(w).doit() == S.true TO6 = Matrix([[S.One, 0, 0, 0, 0], [S.Half, 0, S.Half, 0, 0], [0, S.Half, 0, S.Half, 0], [0, 0, S.Half, 0, S.Half], [0, 0, 0, 0, 1]]) Y6 = DiscreteMarkovChain('Y', trans_probs=TO6) assert Y6.fundamental_matrix() == ImmutableMatrix( [[Rational(3, 2), S.One, S.Half], [S.One, S(2), S.One], [S.Half, S.One, Rational(3, 2)]]) assert Y6.absorbing_probabilities() == ImmutableMatrix( [[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half], [Rational(1, 4), Rational(3, 4)]]) TO7 = Matrix([[Rational(1, 2), Rational(1, 4), Rational(1, 4)], [Rational(1, 2), 0, Rational(1, 2)], [Rational(1, 4), Rational(1, 4), Rational(1, 2)]]) Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) assert Y7.is_absorbing_chain() == False assert Y7.fundamental_matrix() == ImmutableMatrix( [[Rational(86, 75), Rational(1, 25), Rational(-14, 75)], [Rational(2, 25), Rational(21, 25), Rational(2, 25)], [Rational(-14, 75), Rational(1, 25), Rational(86, 75)]]) # test for zero-sized matrix functionality X = DiscreteMarkovChain('X', trans_probs=Matrix([[]])) assert X.number_of_states == 0 assert X.stationary_distribution() == Matrix([[]]) assert X.communication_classes() == [] assert X.canonical_form() == ([], Matrix([[]])) assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]])) assert X.is_regular() == False assert X.is_ergodic() == False # test communication_class # see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing # tutorial 2.pdf TO7 = Matrix([[0, 5, 5, 0, 0], [0, 0, 0, 10, 0], [5, 0, 5, 0, 0], [0, 10, 0, 0, 0], [0, 3, 0, 3, 4]]) / 10 Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) tuples = Y7.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([1, 3], [0, 2], [4]) assert recurrence == (True, False, False) assert periods == (2, 1, 1) TO8 = Matrix([[0, 0, 0, 10, 0, 0], [5, 0, 5, 0, 0, 0], [0, 4, 0, 0, 0, 6], [10, 0, 0, 0, 0, 0], [0, 10, 0, 0, 0, 0], [0, 0, 0, 5, 5, 0] ]) / 10 Y8 = DiscreteMarkovChain('Y', trans_probs=TO8) tuples = Y8.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([0, 3], [1, 2, 5, 4]) assert recurrence == (True, False) assert periods == (2, 2) TO9 = Matrix( [[2, 0, 0, 3, 0, 0, 3, 2, 0, 0], [0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 2, 0, 0, 0, 0, 0, 3, 3], [0, 0, 0, 3, 0, 0, 6, 1, 0, 0], [0, 0, 0, 0, 5, 5, 0, 0, 0, 0], [0, 0, 0, 0, 0, 10, 0, 0, 0, 0], [4, 0, 0, 5, 0, 0, 1, 0, 0, 0], [2, 0, 0, 4, 0, 0, 2, 2, 0, 0], [3, 0, 1, 0, 0, 0, 0, 0, 4, 2], [0, 0, 4, 0, 0, 0, 0, 0, 3, 3]]) / 10 Y9 = DiscreteMarkovChain('Y', trans_probs=TO9) tuples = Y9.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4]) assert recurrence == (True, True, False, True, False) assert periods == (1, 1, 1, 1, 1) # test canonical form # see https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf # example 11.13 T = Matrix([[1, 0, 0, 0, 0], [S(1) / 2, 0, S(1) / 2, 0, 0], [0, S(1) / 2, 0, S(1) / 2, 0], [0, 0, S(1) / 2, 0, S(1) / 2], [0, 0, 0, 0, S(1)]]) DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T) states, A, B, C = DW.decompose() assert states == [0, 4, 1, 2, 3] assert A == Matrix([[1, 0], [0, 1]]) assert B == Matrix([[S(1) / 2, 0], [0, 0], [0, S(1) / 2]]) assert C == Matrix([[0, S(1) / 2, 0], [S(1) / 2, 0, S(1) / 2], [0, S(1) / 2, 0]]) states, new_matrix = DW.canonical_form() assert states == [0, 4, 1, 2, 3] assert new_matrix == Matrix([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [S(1) / 2, 0, 0, S(1) / 2, 0], [0, 0, S(1) / 2, 0, S(1) / 2], [0, S(1) / 2, 0, S(1) / 2, 0]]) # test regular and ergodic # https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf T = Matrix([[0, 4, 0, 0, 0], [1, 0, 3, 0, 0], [0, 2, 0, 2, 0], [0, 0, 3, 0, 1], [0, 0, 0, 4, 0]]) / 4 X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_regular() assert X.is_ergodic() T = Matrix([[0, 1], [1, 0]]) X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_regular() assert X.is_ergodic() # http://www.math.wisc.edu/~valko/courses/331/MC2.pdf T = Matrix([[2, 1, 1], [2, 0, 2], [1, 1, 2]]) / 4 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_regular() assert X.is_ergodic() # https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf T = Matrix([[1, 1], [1, 1]]) / 2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_regular() assert X.is_ergodic() # test is_absorbing_chain T = Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_absorbing_chain() # https://en.wikipedia.org/wiki/Absorbing_Markov_chain T = Matrix([[1, 1, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1], [0, 0, 0, 2]]) / 2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_absorbing_chain() T = Matrix([[2, 0, 0, 0, 0], [1, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 2]]) / 2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_absorbing_chain() # test custom state space Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2) tuples = Y10.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([1], [2, 3]) assert recurrence == (True, False) assert periods == (1, 1) assert Y10.canonical_form() == ([1, 2, 3], TO2) assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) # testing miscellaneous queries T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)], [Rational(1, 3), 0, Rational(2, 3)], [S.Half, S.Half, 0]]) X = DiscreteMarkovChain('X', [0, 1, 2], T) assert P( Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3) assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9) raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T)) # testing miscellaneous queries with different state space X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T) assert P( Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) a = X.state_space.args[0] c = X.state_space.args[2] assert (E(X[1]**2, Eq(X[0], 1)) - (a**2 / 3 + 2 * c**2 / 3)).simplify() == 0 assert (variance(X[1], Eq(X[0], 1)) - (2 * (-a / 3 + c / 3)**2 / 3 + (2 * a / 3 - 2 * c / 3)**2 / 3)).simplify() == 0 raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) #testing queries with multiple RandomIndexedSymbols T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]]) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5) assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2) assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6) assert Float(P(Eq(Y[10], Y[5]), Eq(Y[4], 1)), 14) == Float(1 - P(Ne(Y[10], Y[5]), Eq(Y[4], 1)), 14) assert Float(P(Gt(Y[8], Y[9]), Eq(Y[3], 2)), 14) == Float(1 - P(Le(Y[8], Y[9]), Eq(Y[3], 2)), 14) assert Float(P(Lt(Y[1], Y[4]), Eq(Y[0], 0)), 14) == Float(1 - P(Ge(Y[1], Y[4]), Eq(Y[0], 0)), 14) assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1)) assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1)) assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1)) #test symbolic queries a, b, c, d = symbols('a b c d') T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]]) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) query = P(Eq(Y[a], b), Eq(Y[c], d)) assert query.subs({ a: 10, b: 2, c: 5, d: 1 }).evalf().round(4) == P(Eq(Y[10], 2), Eq(Y[5], 1)).round(4) assert query.subs({ a: 15, b: 0, c: 10, d: 1 }).evalf().round(4) == P(Eq(Y[15], 0), Eq(Y[10], 1)).round(4) query_gt = P(Gt(Y[a], b), Eq(Y[c], d)) query_le = P(Le(Y[a], b), Eq(Y[c], d)) assert query_gt.subs({ a: 5, b: 2, c: 1, d: 0 }).evalf() + query_le.subs({ a: 5, b: 2, c: 1, d: 0 }).evalf() == 1 query_ge = P(Ge(Y[a], b), Eq(Y[c], d)) query_lt = P(Lt(Y[a], b), Eq(Y[c], d)) assert query_ge.subs({ a: 4, b: 1, c: 0, d: 2 }).evalf() + query_lt.subs({ a: 4, b: 1, c: 0, d: 2 }).evalf() == 1 #test issue 20078 assert (2 * Y[1] + 3 * Y[1]).simplify() == 5 * Y[1] assert (2 * Y[1] - 3 * Y[1]).simplify() == -Y[1] assert (2 * (0.25 * Y[1])).simplify() == 0.5 * Y[1] assert ((2 * Y[1]) * (0.25 * Y[1])).simplify() == 0.5 * Y[1]**2 assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1) * Y[1]**2
def ask(proposition, assumptions=True, context=global_assumptions): """ Method for inferring properties about objects. **Syntax** * ask(proposition) * ask(proposition, assumptions) where ``proposition`` is any boolean expression Examples ======== >>> from sympy import ask, Q, pi >>> from sympy.abc import x, y >>> ask(Q.rational(pi)) False >>> ask(Q.even(x*y), Q.even(x) & Q.integer(y)) True >>> ask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) False **Remarks** Relations in assumptions are not implemented (yet), so the following will not give a meaningful result. >>> ask(Q.positive(x), Q.is_true(x > 0)) # doctest: +SKIP It is however a work in progress. """ assumptions = And(assumptions, And(*context)) if isinstance(proposition, AppliedPredicate): key, expr = proposition.func, sympify(proposition.arg) else: key, expr = Q.is_true, sympify(proposition) # direct resolution method, no logic res = key(expr)._eval_ask(assumptions) if res is not None: return res if assumptions is True: return local_facts = _extract_facts(assumptions, expr) if local_facts is None or local_facts is True: return # See if there's a straight-forward conclusion we can make for the inference if local_facts.is_Atom: if key in known_facts_dict[local_facts]: return True if Not(key) in known_facts_dict[local_facts]: return False elif local_facts.func is And and all(k in known_facts_dict for k in local_facts.args): for assum in local_facts.args: if assum.is_Atom: if key in known_facts_dict[assum]: return True if Not(key) in known_facts_dict[assum]: return False elif assum.func is Not and assum.args[0].is_Atom: if key in known_facts_dict[assum]: return False if Not(key) in known_facts_dict[assum]: return True elif (isinstance(key, Predicate) and local_facts.func is Not and local_facts.args[0].is_Atom): if local_facts.args[0] in known_facts_dict[key]: return False # Failing all else, we do a full logical inference return ask_full_inference(key, local_facts, known_facts_cnf)
def test_fcode_Logical(): x, y, z = symbols("x y z") # unary Not assert fcode(Not(x), source_format="free") == ".not. x" # binary And assert fcode(And(x, y), source_format="free") == "x .and. y" assert fcode(And(x, Not(y)), source_format="free") == "x .and. .not. y" assert fcode(And(Not(x), y), source_format="free") == "y .and. .not. x" assert fcode(And(Not(x), Not(y)), source_format="free") == \ ".not. x .and. .not. y" assert fcode(Not(And(x, y), evaluate=False), source_format="free") == \ ".not. (x .and. y)" # binary Or assert fcode(Or(x, y), source_format="free") == "x .or. y" assert fcode(Or(x, Not(y)), source_format="free") == "x .or. .not. y" assert fcode(Or(Not(x), y), source_format="free") == "y .or. .not. x" assert fcode(Or(Not(x), Not(y)), source_format="free") == \ ".not. x .or. .not. y" assert fcode(Not(Or(x, y), evaluate=False), source_format="free") == \ ".not. (x .or. y)" # mixed And/Or assert fcode(And(Or(y, z), x), source_format="free") == "x .and. (y .or. z)" assert fcode(And(Or(z, x), y), source_format="free") == "y .and. (x .or. z)" assert fcode(And(Or(x, y), z), source_format="free") == "z .and. (x .or. y)" assert fcode(Or(And(y, z), x), source_format="free") == "x .or. y .and. z" assert fcode(Or(And(z, x), y), source_format="free") == "y .or. x .and. z" assert fcode(Or(And(x, y), z), source_format="free") == "z .or. x .and. y" # trinary And assert fcode(And(x, y, z), source_format="free") == "x .and. y .and. z" assert fcode(And(x, y, Not(z)), source_format="free") == \ "x .and. y .and. .not. z" assert fcode(And(x, Not(y), z), source_format="free") == \ "x .and. z .and. .not. y" assert fcode(And(Not(x), y, z), source_format="free") == \ "y .and. z .and. .not. x" assert fcode(Not(And(x, y, z), evaluate=False), source_format="free") == \ ".not. (x .and. y .and. z)" # trinary Or assert fcode(Or(x, y, z), source_format="free") == "x .or. y .or. z" assert fcode(Or(x, y, Not(z)), source_format="free") == \ "x .or. y .or. .not. z" assert fcode(Or(x, Not(y), z), source_format="free") == \ "x .or. z .or. .not. y" assert fcode(Or(Not(x), y, z), source_format="free") == \ "y .or. z .or. .not. x" assert fcode(Not(Or(x, y, z), evaluate=False), source_format="free") == \ ".not. (x .or. y .or. z)"
def piecewise_simplify(expr, **kwargs): expr = piecewise_simplify_arguments(expr, **kwargs) if not isinstance(expr, Piecewise): return expr args = list(expr.args) _blessed = lambda e: getattr(e.lhs, '_diff_wrt', False) and (getattr( e.rhs, '_diff_wrt', None) or isinstance(e.rhs, (Rational, NumberSymbol))) for i, (expr, cond) in enumerate(args): # try to simplify conditions and the expression for # equalities that are part of the condition, e.g. # Piecewise((n, And(Eq(n,0), Eq(n + m, 0))), (1, True)) # -> Piecewise((0, And(Eq(n, 0), Eq(m, 0))), (1, True)) if isinstance(cond, And): eqs, other = sift(cond.args, lambda i: isinstance(i, Equality), binary=True) elif isinstance(cond, Equality): eqs, other = [cond], [] else: eqs = other = [] if eqs: eqs = list(ordered(eqs)) for j, e in enumerate(eqs): # these blessed lhs objects behave like Symbols # and the rhs are simple replacements for the "symbols" if _blessed(e): expr = expr.subs(*e.args) eqs[j + 1:] = [ei.subs(*e.args) for ei in eqs[j + 1:]] other = [ei.subs(*e.args) for ei in other] cond = And(*(eqs + other)) args[i] = args[i].func(expr, cond) # See if expressions valid for an Equal expression happens to evaluate # to the same function as in the next piecewise segment, see: # https://github.com/sympy/sympy/issues/8458 prevexpr = None for i, (expr, cond) in reversed(list(enumerate(args))): if prevexpr is not None: if isinstance(cond, And): eqs, other = sift(cond.args, lambda i: isinstance(i, Equality), binary=True) elif isinstance(cond, Equality): eqs, other = [cond], [] else: eqs = other = [] _prevexpr = prevexpr _expr = expr if eqs and not other: eqs = list(ordered(eqs)) for e in eqs: # these blessed lhs objects behave like Symbols # and the rhs are simple replacements for the "symbols" if _blessed(e): _prevexpr = _prevexpr.subs(*e.args) _expr = _expr.subs(*e.args) # Did it evaluate to the same? if _prevexpr == _expr: # Set the expression for the Not equal section to the same # as the next. These will be merged when creating the new # Piecewise args[i] = args[i].func(args[i + 1][0], cond) else: # Update the expression that we compare against prevexpr = expr else: prevexpr = expr return Piecewise(*args)
def test_bool_minterm(): x, y = symbols('x,y') assert bool_minterm(3, [x, y]) == And(x, y) assert bool_minterm([1, 0], [x, y]) == And(Not(y), x)