def _(expr): base, exp = expr.base, expr.exp return [ (Q.real(base) & Q.even(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), (Q.nonnegative(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), (Q.nonpositive(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonpositive(expr), Equivalent(Q.zero(expr), Q.zero(base) & Q.positive(exp)) ]
def _(expr): arg = expr.args[0] return [Q.nonnegative(expr), Equivalent(~Q.zero(arg), ~Q.zero(expr)), Q.even(arg) >> Q.even(expr), Q.odd(arg) >> Q.odd(expr), Q.integer(arg) >> Q.integer(expr), ]
def _(expr): return [Equivalent(Q.zero(expr), anyarg(x, Q.zero(x), expr)), allarg(x, Q.positive(x), expr) >> Q.positive(expr), allarg(x, Q.real(x), expr) >> Q.real(expr), allarg(x, Q.rational(x), expr) >> Q.rational(expr), allarg(x, Q.integer(x), expr) >> Q.integer(expr), exactlyonearg(x, ~Q.rational(x), expr) >> ~Q.integer(expr), allarg(x, Q.commutative(x), expr) >> Q.commutative(expr), ]
def test_atan2(): assert refine(atan2(y, x), Q.real(y) & Q.positive(x)) == atan(y/x) assert refine(atan2(y, x), Q.negative(y) & Q.positive(x)) == atan(y/x) assert refine(atan2(y, x), Q.negative(y) & Q.negative(x)) == atan(y/x) - pi assert refine(atan2(y, x), Q.positive(y) & Q.negative(x)) == atan(y/x) + pi assert refine(atan2(y, x), Q.zero(y) & Q.negative(x)) == pi assert refine(atan2(y, x), Q.positive(y) & Q.zero(x)) == pi/2 assert refine(atan2(y, x), Q.negative(y) & Q.zero(x)) == -pi/2 assert refine(atan2(y, x), Q.zero(y) & Q.zero(x)) is nan
def test_is_literal(): assert is_literal(True) is True assert is_literal(False) is True assert is_literal(A) is True assert is_literal(~A) is True assert is_literal(Or(A, B)) is False assert is_literal(Q.zero(A)) is True assert is_literal(Not(Q.zero(A))) is True assert is_literal(Or(A, B)) is False assert is_literal(And(Q.zero(A), Q.zero(B))) is False
def test_zero_positive(): assert satask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False assert satask(Q.positive(x) & Q.positive(y), Q.zero(x + y)) is False assert satask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True assert satask(Q.positive(x) & Q.positive(y), Q.nonzero(x + y)) is None # This one requires several levels of forward chaining assert satask(Q.zero(x*(x + y)), Q.positive(x) & Q.positive(y)) is False assert satask(Q.positive(pi*x*y + 1), Q.positive(x) & Q.positive(y)) is True assert satask(Q.positive(pi*x*y - 5), Q.positive(x) & Q.positive(y)) is None
def test_extract_predargs(): props = CNF.from_prop(Q.zero(Abs(x*y)) & Q.zero(x*y)) assump = CNF.from_prop(Q.zero(x)) context = CNF.from_prop(Q.zero(y)) assert extract_predargs(props) == {Abs(x*y), x*y} assert extract_predargs(props, assump) == {Abs(x*y), x*y, x} assert extract_predargs(props, assump, context) == {Abs(x*y), x*y, x, y} props = CNF.from_prop(Eq(x, y)) assump = CNF.from_prop(Gt(y, z)) assert extract_predargs(props, assump) == {x, y, z}
def test_zero_pow(): assert satask(Q.zero(x**y), Q.zero(x) & Q.positive(y)) is True assert satask(Q.zero(x**y), Q.nonzero(x) & Q.zero(y)) is False assert satask(Q.zero(x), Q.zero(x**y)) is True assert satask(Q.zero(x**y), Q.zero(x)) is None
def test_abs(): assert satask(Q.nonnegative(abs(x))) is True assert satask(Q.positive(abs(x)), ~Q.zero(x)) is True assert satask(Q.zero(x), ~Q.zero(abs(x))) is False assert satask(Q.zero(x), Q.zero(abs(x))) is True assert satask(Q.nonzero(x), ~Q.zero(abs(x))) is None # x could be complex assert satask(Q.zero(abs(x)), Q.zero(x)) is True
def test_sign(): x = Symbol('x', real = True) assert refine(sign(x), Q.positive(x)) == 1 assert refine(sign(x), Q.negative(x)) == -1 assert refine(sign(x), Q.zero(x)) == 0 assert refine(sign(x), True) == sign(x) assert refine(sign(Abs(x)), Q.nonzero(x)) == 1 x = Symbol('x', imaginary=True) assert refine(sign(x), Q.positive(im(x))) == S.ImaginaryUnit assert refine(sign(x), Q.negative(im(x))) == -S.ImaginaryUnit assert refine(sign(x), True) == sign(x) x = Symbol('x', complex=True) assert refine(sign(x), Q.zero(x)) == 0
def test_get_relevant_clsfacts(): exprs = {Abs(x*y)} exprs, facts = get_relevant_clsfacts(exprs) assert exprs == {x*y} assert facts.clauses == \ {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True), Literal(Q.odd(Abs(x*y)), False)}), frozenset({Literal(Q.positive(Abs(x*y)), False), Literal(Q.zero(Abs(x*y)), False)})}
def test_is_eq(): # test assumptions assert is_eq(x, y, Q.infinite(x) & Q.finite(y)) is False assert is_eq( x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_real(x) & ~Q.extended_real(y)) is False assert is_eq( x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_positive(x) & Q.extended_negative(y)) is False assert is_eq(x + I, y + I, Q.infinite(x) & Q.finite(y)) is False assert is_eq(1 + x * I, 1 + y * I, Q.infinite(x) & Q.finite(y)) is False assert is_eq(x, S(0), assumptions=Q.zero(x)) assert is_eq(x, S(0), assumptions=~Q.zero(x)) is False assert is_eq(x, S(0), assumptions=Q.nonzero(x)) is False assert is_neq(x, S(0), assumptions=Q.zero(x)) is False assert is_neq(x, S(0), assumptions=~Q.zero(x)) assert is_neq(x, S(0), assumptions=Q.nonzero(x)) # test registration class PowTest(Expr): def __new__(cls, base, exp): return Basic.__new__(cls, _sympify(base), _sympify(exp)) @dispatch(PowTest, PowTest) def _eval_is_eq(lhs, rhs): if type(lhs) == PowTest and type(rhs) == PowTest: return fuzzy_and([ is_eq(lhs.args[0], rhs.args[0]), is_eq(lhs.args[1], rhs.args[1]) ]) assert is_eq(PowTest(3, 4), PowTest(3, 4)) assert is_eq(PowTest(3, 4), _sympify(4)) is None assert is_neq(PowTest(3, 4), PowTest(3, 7))
def test_old_assump(): assert satask(Q.positive(1)) is True assert satask(Q.positive(-1)) is False assert satask(Q.positive(0)) is False assert satask(Q.positive(I)) is False assert satask(Q.positive(pi)) is True assert satask(Q.negative(1)) is False assert satask(Q.negative(-1)) is True assert satask(Q.negative(0)) is False assert satask(Q.negative(I)) is False assert satask(Q.negative(pi)) is False assert satask(Q.zero(1)) is False assert satask(Q.zero(-1)) is False assert satask(Q.zero(0)) is True assert satask(Q.zero(I)) is False assert satask(Q.zero(pi)) is False assert satask(Q.nonzero(1)) is True assert satask(Q.nonzero(-1)) is True assert satask(Q.nonzero(0)) is False assert satask(Q.nonzero(I)) is False assert satask(Q.nonzero(pi)) is True assert satask(Q.nonpositive(1)) is False assert satask(Q.nonpositive(-1)) is True assert satask(Q.nonpositive(0)) is True assert satask(Q.nonpositive(I)) is False assert satask(Q.nonpositive(pi)) is False assert satask(Q.nonnegative(1)) is True assert satask(Q.nonnegative(-1)) is False assert satask(Q.nonnegative(0)) is True assert satask(Q.nonnegative(I)) is False assert satask(Q.nonnegative(pi)) is True
def test_satask(): # No relevant facts assert satask(Q.real(x), Q.real(x)) is True assert satask(Q.real(x), ~Q.real(x)) is False assert satask(Q.real(x)) is None assert satask(Q.real(x), Q.positive(x)) is True assert satask(Q.positive(x), Q.real(x)) is None assert satask(Q.real(x), ~Q.positive(x)) is None assert satask(Q.positive(x), ~Q.real(x)) is False raises(ValueError, lambda: satask(Q.real(x), Q.real(x) & ~Q.real(x))) with assuming(Q.positive(x)): assert satask(Q.real(x)) is True assert satask(~Q.positive(x)) is False raises(ValueError, lambda: satask(Q.real(x), ~Q.positive(x))) assert satask(Q.zero(x), Q.nonzero(x)) is False assert satask(Q.positive(x), Q.zero(x)) is False assert satask(Q.real(x), Q.zero(x)) is True assert satask(Q.zero(x), Q.zero(x*y)) is None assert satask(Q.zero(x*y), Q.zero(x))
)), ), ( Pow, CustomLambda(lambda power: Implies( Q.nonpositive(power.base) & Q.odd(power.exp) & Q.nonnegative(power. exp), Q.nonpositive(power), )), ), # This one can still be made easier to read. I think we need basic pattern # matching, so that we can just write Equivalent(Q.zero(x**y), Q.zero(x) & Q.positive(y)) ( Pow, CustomLambda(lambda power: Equivalent( Q.zero(power), Q.zero(power.base) & Q.positive(power.exp))), ), (Integer, CheckIsPrime(Q.prime)), (Integer, CheckOldAssump(Q.composite)), # Implicitly assumes Mul has more than one arg # Would be AllArgs(Q.prime | Q.composite) except 1 is composite (Mul, Implies(AllArgs(Q.prime), ~Q.prime)), # More advanced prime assumptions will require inequalities, as 1 provides # a corner case. ( Mul, Implies( AllArgs(Q.imaginary | Q.real), Implies(ExactlyOneArg(Q.imaginary), Q.imaginary), ),
def test_zero(): """ Everything in this test doesn't work with the ask handlers, and most things would be very difficult or impossible to make work under that model. """ assert satask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True assert satask(Q.zero(x*y), Q.zero(x) | Q.zero(y)) is True assert satask(Implies(Q.zero(x), Q.zero(x*y))) is True # This one in particular requires computing the fixed-point of the # relevant facts, because going from Q.nonzero(x*y) -> ~Q.zero(x*y) and # Q.zero(x*y) -> Equivalent(Q.zero(x*y), Q.zero(x) | Q.zero(y)) takes two # steps. assert satask(Q.zero(x) | Q.zero(y), Q.nonzero(x*y)) is False assert satask(Q.zero(x), Q.zero(x**2)) is True
def register_fact(klass, fact, registry=fact_registry): registry[klass] |= set([fact]) for klass, fact in [ (Mul, Equivalent(Q.zero, AnyArgs(Q.zero))), (MatMul, Implies(AllArgs(Q.square), Equivalent(Q.invertible, AllArgs(Q.invertible)))), (Add, Implies(AllArgs(Q.positive), Q.positive)), (Add, Implies(AllArgs(Q.negative), Q.negative)), (Mul, Implies(AllArgs(Q.positive), Q.positive)), (Mul, Implies(AllArgs(Q.commutative), Q.commutative)), (Mul, Implies(AllArgs(Q.real), Q.commutative)), # This one can still be made easier to read. I think we need basic pattern # matching, so that we can just write Equivalent(Q.zero(x**y), Q.zero(x) & Q.positive(y)) (Pow, CustomLambda(lambda power: Equivalent(Q.zero(power), Q.zero(power.base) & Q.positive(power.exp)))), (Integer, CheckIsPrime(Q.prime)), # Implicitly assumes Mul has more than one arg # Would be AllArgs(Q.prime | Q.composite) except 1 is composite (Mul, Implies(AllArgs(Q.prime), ~Q.prime)), # More advanced prime assumptions will require inequalities, as 1 provides # a corner case. (Mul, Implies(AllArgs(Q.imaginary | Q.real), Implies(ExactlyOneArg(Q.imaginary), Q.imaginary))), (Mul, Implies(AllArgs(Q.real), Q.real)), (Add, Implies(AllArgs(Q.real), Q.real)), #General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) (Mul, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational), Q.irrational))), (Add, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational), Q.irrational))), (Mul, Implies(AllArgs(Q.rational), Q.rational)),
(Mul, Equivalent(Q.zero, AnyArgs(Q.zero))), (MatMul, Implies(AllArgs(Q.square), Equivalent(Q.invertible, AllArgs(Q.invertible)))), (Add, Implies(AllArgs(Q.positive), Q.positive)), (Add, Implies(AllArgs(Q.negative), Q.negative)), (Mul, Implies(AllArgs(Q.positive), Q.positive)), (Mul, Implies(AllArgs(Q.commutative), Q.commutative)), (Mul, Implies(AllArgs(Q.real), Q.commutative)), (Pow, CustomLambda(lambda power: Implies(Q.real(power.base) & Q.even(power.exp) & Q.nonnegative(power.exp), Q.nonnegative(power)))), (Pow, CustomLambda(lambda power: Implies(Q.nonnegative(power.base) & Q.odd(power.exp) & Q.nonnegative(power.exp), Q.nonnegative(power)))), (Pow, CustomLambda(lambda power: Implies(Q.nonpositive(power.base) & Q.odd(power.exp) & Q.nonnegative(power.exp), Q.nonpositive(power)))), # This one can still be made easier to read. I think we need basic pattern # matching, so that we can just write Equivalent(Q.zero(x**y), Q.zero(x) & Q.positive(y)) (Pow, CustomLambda(lambda power: Equivalent(Q.zero(power), Q.zero(power.base) & Q.positive(power.exp)))), (Integer, CheckIsPrime(Q.prime)), # Implicitly assumes Mul has more than one arg # Would be AllArgs(Q.prime | Q.composite) except 1 is composite (Mul, Implies(AllArgs(Q.prime), ~Q.prime)), # More advanced prime assumptions will require inequalities, as 1 provides # a corner case. (Mul, Implies(AllArgs(Q.imaginary | Q.real), Implies(ExactlyOneArg(Q.imaginary), Q.imaginary))), (Mul, Implies(AllArgs(Q.real), Q.real)), (Add, Implies(AllArgs(Q.real), Q.real)), # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) (Mul, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational), Q.irrational))), (Add, Implies(AllArgs(Q.real), Implies(ExactlyOneArg(Q.irrational), Q.irrational))), (Mul, Implies(AllArgs(Q.rational), Q.rational)),
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
Q.real(power.base) & Q.even(power.exp) & Q.nonnegative(power.exp), Q.nonnegative(power)))), (Pow, CustomLambda(lambda power: Implies( Q.nonnegative(power.base) & Q.odd(power.exp) & Q.nonnegative( power.exp), Q.nonnegative(power)))), (Pow, CustomLambda(lambda power: Implies( Q.nonpositive(power.base) & Q.odd(power.exp) & Q.nonnegative( power.exp), Q.nonpositive(power)))), # This one can still be made easier to read. I think we need basic pattern # matching, so that we can just write Equivalent(Q.zero(x**y), Q.zero(x) & Q.positive(y)) (Pow, CustomLambda( lambda power: Equivalent(Q.zero(power), Q.zero(power.base) & Q.positive(power.exp))) ), (Integer, CheckIsPrime(Q.prime)), # Implicitly assumes Mul has more than one arg # Would be AllArgs(Q.prime | Q.composite) except 1 is composite (Mul, Implies(AllArgs(Q.prime), ~Q.prime)), # More advanced prime assumptions will require inequalities, as 1 provides # a corner case. (Mul, Implies(AllArgs(Q.imaginary | Q.real), Implies(ExactlyOneArg(Q.imaginary), Q.imaginary))), (Mul, Implies(AllArgs(Q.real), Q.real)), (Add, Implies(AllArgs(Q.real), Q.real)), # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) (Mul,
def test_satisfiable_non_symbols(): x, y = symbols('x y') assumptions = Q.zero(x * y) facts = Implies(Q.zero(x * y), Q.zero(x) | Q.zero(y)) query = ~Q.zero(x) & ~Q.zero(y) refutations = [{ Q.zero(x): True, Q.zero(x * y): True }, { Q.zero(y): True, Q.zero(x * y): True }, { Q.zero(x): True, Q.zero(y): True, Q.zero(x * y): True }, { Q.zero(x): True, Q.zero(y): False, Q.zero(x * y): True }, { Q.zero(x): False, Q.zero(y): True, Q.zero(x * y): True }] assert not satisfiable(And(assumptions, facts, query), algorithm='dpll') assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll') in refutations assert not satisfiable(And(assumptions, facts, query), algorithm='dpll2') assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll2') in refutations
def test_exactlyonearg(): assert exactlyonearg(x, Q.zero(x), x*y) == \ Or(Q.zero(x) & ~Q.zero(y), Q.zero(y) & ~Q.zero(x)) assert exactlyonearg(x, Q.zero(x), x*y*z) == \ Or(Q.zero(x) & ~Q.zero(y) & ~Q.zero(z), Q.zero(y) & ~Q.zero(x) & ~Q.zero(z), Q.zero(z) & ~Q.zero(x) & ~Q.zero(y)) assert exactlyonearg(x, Q.positive(x) | Q.negative(x), x*y) == \ Or((Q.positive(x) | Q.negative(x)) & ~(Q.positive(y) | Q.negative(y)), (Q.positive(y) | Q.negative(y)) & ~(Q.positive(x) | Q.negative(x)))
def test_anyarg(): assert anyarg(x, Q.zero(x), x * y) == Or(Q.zero(x), Q.zero(y)) assert anyarg(x, Q.positive(x) & Q.negative(x), x*y) == \ Or(Q.positive(x) & Q.negative(x), Q.positive(y) & Q.negative(y))
def test_allargs(): assert allargs(x, Q.zero(x), x * y) == And(Q.zero(x), Q.zero(y)) assert allargs(x, Q.positive(x) | Q.negative(x), x * y) == And( Q.positive(x) | Q.negative(x), Q.positive(y) | Q.negative(y))