AI Newsletter Digest improvements: fixed QP soft line break decoding, URL extraction, and content cleaning
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
"""
|
||||
rename this to test_assumptions.py when the old assumptions system is deleted
|
||||
"""
|
||||
from sympy.abc import x, y
|
||||
from sympy.assumptions.assume import global_assumptions
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.printing import pretty
|
||||
|
||||
|
||||
def test_equal():
|
||||
"""Test for equality"""
|
||||
assert Q.positive(x) == Q.positive(x)
|
||||
assert Q.positive(x) != ~Q.positive(x)
|
||||
assert ~Q.positive(x) == ~Q.positive(x)
|
||||
|
||||
|
||||
def test_pretty():
|
||||
assert pretty(Q.positive(x)) == "Q.positive(x)"
|
||||
assert pretty(
|
||||
{Q.positive, Q.integer}) == "{Q.integer, Q.positive}"
|
||||
|
||||
|
||||
def test_global():
|
||||
"""Test for global assumptions"""
|
||||
global_assumptions.add(x > 0)
|
||||
assert (x > 0) in global_assumptions
|
||||
global_assumptions.remove(x > 0)
|
||||
assert not (x > 0) in global_assumptions
|
||||
# same with multiple of assumptions
|
||||
global_assumptions.add(x > 0, y > 0)
|
||||
assert (x > 0) in global_assumptions
|
||||
assert (y > 0) in global_assumptions
|
||||
global_assumptions.clear()
|
||||
assert not (x > 0) in global_assumptions
|
||||
assert not (y > 0) in global_assumptions
|
||||
@@ -0,0 +1,39 @@
|
||||
from sympy.assumptions import ask, Q
|
||||
from sympy.assumptions.assume import assuming, global_assumptions
|
||||
from sympy.abc import x, y
|
||||
|
||||
def test_assuming():
|
||||
with assuming(Q.integer(x)):
|
||||
assert ask(Q.integer(x))
|
||||
assert not ask(Q.integer(x))
|
||||
|
||||
def test_assuming_nested():
|
||||
assert not ask(Q.integer(x))
|
||||
assert not ask(Q.integer(y))
|
||||
with assuming(Q.integer(x)):
|
||||
assert ask(Q.integer(x))
|
||||
assert not ask(Q.integer(y))
|
||||
with assuming(Q.integer(y)):
|
||||
assert ask(Q.integer(x))
|
||||
assert ask(Q.integer(y))
|
||||
assert ask(Q.integer(x))
|
||||
assert not ask(Q.integer(y))
|
||||
assert not ask(Q.integer(x))
|
||||
assert not ask(Q.integer(y))
|
||||
|
||||
def test_finally():
|
||||
try:
|
||||
with assuming(Q.integer(x)):
|
||||
1/0
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
assert not ask(Q.integer(x))
|
||||
|
||||
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
|
||||
@@ -0,0 +1,283 @@
|
||||
from sympy.assumptions.ask import (Q, ask)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.matrices.expressions.diagonal import (DiagMatrix, DiagonalMatrix)
|
||||
from sympy.matrices.dense import Matrix
|
||||
from sympy.matrices.expressions import (MatrixSymbol, Identity, ZeroMatrix,
|
||||
OneMatrix, Trace, MatrixSlice, Determinant, BlockMatrix, BlockDiagMatrix)
|
||||
from sympy.matrices.expressions.factorizations import LofLU
|
||||
from sympy.testing.pytest import XFAIL
|
||||
|
||||
X = MatrixSymbol('X', 2, 2)
|
||||
Y = MatrixSymbol('Y', 2, 3)
|
||||
Z = MatrixSymbol('Z', 2, 2)
|
||||
A1x1 = MatrixSymbol('A1x1', 1, 1)
|
||||
B1x1 = MatrixSymbol('B1x1', 1, 1)
|
||||
C0x0 = MatrixSymbol('C0x0', 0, 0)
|
||||
V1 = MatrixSymbol('V1', 2, 1)
|
||||
V2 = MatrixSymbol('V2', 2, 1)
|
||||
|
||||
def test_square():
|
||||
assert ask(Q.square(X))
|
||||
assert not ask(Q.square(Y))
|
||||
assert ask(Q.square(Y*Y.T))
|
||||
|
||||
def test_invertible():
|
||||
assert ask(Q.invertible(X), Q.invertible(X))
|
||||
assert ask(Q.invertible(Y)) is False
|
||||
assert ask(Q.invertible(X*Y), Q.invertible(X)) is False
|
||||
assert ask(Q.invertible(X*Z), Q.invertible(X)) is None
|
||||
assert ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z)) is True
|
||||
assert ask(Q.invertible(X.T)) is None
|
||||
assert ask(Q.invertible(X.T), Q.invertible(X)) is True
|
||||
assert ask(Q.invertible(X.I)) is True
|
||||
assert ask(Q.invertible(Identity(3))) is True
|
||||
assert ask(Q.invertible(ZeroMatrix(3, 3))) is False
|
||||
assert ask(Q.invertible(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.invertible(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.invertible(X), Q.fullrank(X) & Q.square(X))
|
||||
|
||||
def test_singular():
|
||||
assert ask(Q.singular(X)) is None
|
||||
assert ask(Q.singular(X), Q.invertible(X)) is False
|
||||
assert ask(Q.singular(X), ~Q.invertible(X)) is True
|
||||
|
||||
@XFAIL
|
||||
def test_invertible_fullrank():
|
||||
assert ask(Q.invertible(X), Q.fullrank(X)) is True
|
||||
|
||||
|
||||
def test_invertible_BlockMatrix():
|
||||
assert ask(Q.invertible(BlockMatrix([Identity(3)]))) == True
|
||||
assert ask(Q.invertible(BlockMatrix([ZeroMatrix(3, 3)]))) == False
|
||||
|
||||
X = Matrix([[1, 2, 3], [3, 5, 4]])
|
||||
Y = Matrix([[4, 2, 7], [2, 3, 5]])
|
||||
# non-invertible A block
|
||||
assert ask(Q.invertible(BlockMatrix([
|
||||
[Matrix.ones(3, 3), Y.T],
|
||||
[X, Matrix.eye(2)],
|
||||
]))) == True
|
||||
# non-invertible B block
|
||||
assert ask(Q.invertible(BlockMatrix([
|
||||
[Y.T, Matrix.ones(3, 3)],
|
||||
[Matrix.eye(2), X],
|
||||
]))) == True
|
||||
# non-invertible C block
|
||||
assert ask(Q.invertible(BlockMatrix([
|
||||
[X, Matrix.eye(2)],
|
||||
[Matrix.ones(3, 3), Y.T],
|
||||
]))) == True
|
||||
# non-invertible D block
|
||||
assert ask(Q.invertible(BlockMatrix([
|
||||
[Matrix.eye(2), X],
|
||||
[Y.T, Matrix.ones(3, 3)],
|
||||
]))) == True
|
||||
|
||||
|
||||
def test_invertible_BlockDiagMatrix():
|
||||
assert ask(Q.invertible(BlockDiagMatrix(Identity(3), Identity(5)))) == True
|
||||
assert ask(Q.invertible(BlockDiagMatrix(ZeroMatrix(3, 3), Identity(5)))) == False
|
||||
assert ask(Q.invertible(BlockDiagMatrix(Identity(3), OneMatrix(5, 5)))) == False
|
||||
|
||||
|
||||
def test_symmetric():
|
||||
assert ask(Q.symmetric(X), Q.symmetric(X))
|
||||
assert ask(Q.symmetric(X*Z), Q.symmetric(X)) is None
|
||||
assert ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z)) is True
|
||||
assert ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) is True
|
||||
assert ask(Q.symmetric(Y)) is False
|
||||
assert ask(Q.symmetric(Y*Y.T)) is True
|
||||
assert ask(Q.symmetric(Y.T*X*Y)) is None
|
||||
assert ask(Q.symmetric(Y.T*X*Y), Q.symmetric(X)) is True
|
||||
assert ask(Q.symmetric(X**10), Q.symmetric(X)) is True
|
||||
assert ask(Q.symmetric(A1x1)) is True
|
||||
assert ask(Q.symmetric(A1x1 + B1x1)) is True
|
||||
assert ask(Q.symmetric(A1x1 * B1x1)) is True
|
||||
assert ask(Q.symmetric(V1.T*V1)) is True
|
||||
assert ask(Q.symmetric(V1.T*(V1 + V2))) is True
|
||||
assert ask(Q.symmetric(V1.T*(V1 + V2) + A1x1)) is True
|
||||
assert ask(Q.symmetric(MatrixSlice(Y, (0, 1), (1, 2)))) is True
|
||||
assert ask(Q.symmetric(Identity(3))) is True
|
||||
assert ask(Q.symmetric(ZeroMatrix(3, 3))) is True
|
||||
assert ask(Q.symmetric(OneMatrix(3, 3))) is True
|
||||
|
||||
def _test_orthogonal_unitary(predicate):
|
||||
assert ask(predicate(X), predicate(X))
|
||||
assert ask(predicate(X.T), predicate(X)) is True
|
||||
assert ask(predicate(X.I), predicate(X)) is True
|
||||
assert ask(predicate(X**2), predicate(X))
|
||||
assert ask(predicate(Y)) is False
|
||||
assert ask(predicate(X)) is None
|
||||
assert ask(predicate(X), ~Q.invertible(X)) is False
|
||||
assert ask(predicate(X*Z*X), predicate(X) & predicate(Z)) is True
|
||||
assert ask(predicate(Identity(3))) is True
|
||||
assert ask(predicate(ZeroMatrix(3, 3))) is False
|
||||
assert ask(Q.invertible(X), predicate(X))
|
||||
assert not ask(predicate(X + Z), predicate(X) & predicate(Z))
|
||||
|
||||
def test_orthogonal():
|
||||
_test_orthogonal_unitary(Q.orthogonal)
|
||||
|
||||
def test_unitary():
|
||||
_test_orthogonal_unitary(Q.unitary)
|
||||
assert ask(Q.unitary(X), Q.orthogonal(X))
|
||||
|
||||
def test_fullrank():
|
||||
assert ask(Q.fullrank(X), Q.fullrank(X))
|
||||
assert ask(Q.fullrank(X**2), Q.fullrank(X))
|
||||
assert ask(Q.fullrank(X.T), Q.fullrank(X)) is True
|
||||
assert ask(Q.fullrank(X)) is None
|
||||
assert ask(Q.fullrank(Y)) is None
|
||||
assert ask(Q.fullrank(X*Z), Q.fullrank(X) & Q.fullrank(Z)) is True
|
||||
assert ask(Q.fullrank(Identity(3))) is True
|
||||
assert ask(Q.fullrank(ZeroMatrix(3, 3))) is False
|
||||
assert ask(Q.fullrank(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.fullrank(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.invertible(X), ~Q.fullrank(X)) == False
|
||||
|
||||
|
||||
def test_positive_definite():
|
||||
assert ask(Q.positive_definite(X), Q.positive_definite(X))
|
||||
assert ask(Q.positive_definite(X.T), Q.positive_definite(X)) is True
|
||||
assert ask(Q.positive_definite(X.I), Q.positive_definite(X)) is True
|
||||
assert ask(Q.positive_definite(Y)) is False
|
||||
assert ask(Q.positive_definite(X)) is None
|
||||
assert ask(Q.positive_definite(X**3), Q.positive_definite(X))
|
||||
assert ask(Q.positive_definite(X*Z*X),
|
||||
Q.positive_definite(X) & Q.positive_definite(Z)) is True
|
||||
assert ask(Q.positive_definite(X), Q.orthogonal(X))
|
||||
assert ask(Q.positive_definite(Y.T*X*Y),
|
||||
Q.positive_definite(X) & Q.fullrank(Y)) is True
|
||||
assert not ask(Q.positive_definite(Y.T*X*Y), Q.positive_definite(X))
|
||||
assert ask(Q.positive_definite(Identity(3))) is True
|
||||
assert ask(Q.positive_definite(ZeroMatrix(3, 3))) is False
|
||||
assert ask(Q.positive_definite(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.positive_definite(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.positive_definite(X + Z), Q.positive_definite(X) &
|
||||
Q.positive_definite(Z)) is True
|
||||
assert not ask(Q.positive_definite(-X), Q.positive_definite(X))
|
||||
assert ask(Q.positive(X[1, 1]), Q.positive_definite(X))
|
||||
|
||||
def test_triangular():
|
||||
assert ask(Q.upper_triangular(X + Z.T + Identity(2)), Q.upper_triangular(X) &
|
||||
Q.lower_triangular(Z)) is True
|
||||
assert ask(Q.upper_triangular(X*Z.T), Q.upper_triangular(X) &
|
||||
Q.lower_triangular(Z)) is True
|
||||
assert ask(Q.lower_triangular(Identity(3))) is True
|
||||
assert ask(Q.lower_triangular(ZeroMatrix(3, 3))) is True
|
||||
assert ask(Q.upper_triangular(ZeroMatrix(3, 3))) is True
|
||||
assert ask(Q.lower_triangular(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.upper_triangular(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.lower_triangular(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.upper_triangular(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.triangular(X), Q.unit_triangular(X))
|
||||
assert ask(Q.upper_triangular(X**3), Q.upper_triangular(X))
|
||||
assert ask(Q.lower_triangular(X**3), Q.lower_triangular(X))
|
||||
|
||||
|
||||
def test_diagonal():
|
||||
assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) &
|
||||
Q.diagonal(Z)) is True
|
||||
assert ask(Q.diagonal(ZeroMatrix(3, 3)))
|
||||
assert ask(Q.diagonal(OneMatrix(1, 1))) is True
|
||||
assert ask(Q.diagonal(OneMatrix(3, 3))) is False
|
||||
assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X))
|
||||
assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X))
|
||||
assert ask(Q.symmetric(X), Q.diagonal(X))
|
||||
assert ask(Q.triangular(X), Q.diagonal(X))
|
||||
assert ask(Q.diagonal(C0x0))
|
||||
assert ask(Q.diagonal(A1x1))
|
||||
assert ask(Q.diagonal(A1x1 + B1x1))
|
||||
assert ask(Q.diagonal(A1x1*B1x1))
|
||||
assert ask(Q.diagonal(V1.T*V2))
|
||||
assert ask(Q.diagonal(V1.T*(X + Z)*V1))
|
||||
assert ask(Q.diagonal(MatrixSlice(Y, (0, 1), (1, 2)))) is True
|
||||
assert ask(Q.diagonal(V1.T*(V1 + V2))) is True
|
||||
assert ask(Q.diagonal(X**3), Q.diagonal(X))
|
||||
assert ask(Q.diagonal(Identity(3)))
|
||||
assert ask(Q.diagonal(DiagMatrix(V1)))
|
||||
assert ask(Q.diagonal(DiagonalMatrix(X)))
|
||||
|
||||
|
||||
def test_non_atoms():
|
||||
assert ask(Q.real(Trace(X)), Q.positive(Trace(X)))
|
||||
|
||||
@XFAIL
|
||||
def test_non_trivial_implies():
|
||||
X = MatrixSymbol('X', 3, 3)
|
||||
Y = MatrixSymbol('Y', 3, 3)
|
||||
assert ask(Q.lower_triangular(X+Y), Q.lower_triangular(X) &
|
||||
Q.lower_triangular(Y)) is True
|
||||
assert ask(Q.triangular(X), Q.lower_triangular(X)) is True
|
||||
assert ask(Q.triangular(X+Y), Q.lower_triangular(X) &
|
||||
Q.lower_triangular(Y)) is True
|
||||
|
||||
def test_MatrixSlice():
|
||||
X = MatrixSymbol('X', 4, 4)
|
||||
B = MatrixSlice(X, (1, 3), (1, 3))
|
||||
C = MatrixSlice(X, (0, 3), (1, 3))
|
||||
assert ask(Q.symmetric(B), Q.symmetric(X))
|
||||
assert ask(Q.invertible(B), Q.invertible(X))
|
||||
assert ask(Q.diagonal(B), Q.diagonal(X))
|
||||
assert ask(Q.orthogonal(B), Q.orthogonal(X))
|
||||
assert ask(Q.upper_triangular(B), Q.upper_triangular(X))
|
||||
|
||||
assert not ask(Q.symmetric(C), Q.symmetric(X))
|
||||
assert not ask(Q.invertible(C), Q.invertible(X))
|
||||
assert not ask(Q.diagonal(C), Q.diagonal(X))
|
||||
assert not ask(Q.orthogonal(C), Q.orthogonal(X))
|
||||
assert not ask(Q.upper_triangular(C), Q.upper_triangular(X))
|
||||
|
||||
def test_det_trace_positive():
|
||||
X = MatrixSymbol('X', 4, 4)
|
||||
assert ask(Q.positive(Trace(X)), Q.positive_definite(X))
|
||||
assert ask(Q.positive(Determinant(X)), Q.positive_definite(X))
|
||||
|
||||
def test_field_assumptions():
|
||||
X = MatrixSymbol('X', 4, 4)
|
||||
Y = MatrixSymbol('Y', 4, 4)
|
||||
assert ask(Q.real_elements(X), Q.real_elements(X))
|
||||
assert not ask(Q.integer_elements(X), Q.real_elements(X))
|
||||
assert ask(Q.complex_elements(X), Q.real_elements(X))
|
||||
assert ask(Q.complex_elements(X**2), Q.real_elements(X))
|
||||
assert ask(Q.real_elements(X**2), Q.integer_elements(X))
|
||||
assert ask(Q.real_elements(X+Y), Q.real_elements(X)) is None
|
||||
assert ask(Q.real_elements(X+Y), Q.real_elements(X) & Q.real_elements(Y))
|
||||
from sympy.matrices.expressions.hadamard import HadamardProduct
|
||||
assert ask(Q.real_elements(HadamardProduct(X, Y)),
|
||||
Q.real_elements(X) & Q.real_elements(Y))
|
||||
assert ask(Q.complex_elements(X+Y), Q.real_elements(X) & Q.complex_elements(Y))
|
||||
|
||||
assert ask(Q.real_elements(X.T), Q.real_elements(X))
|
||||
assert ask(Q.real_elements(X.I), Q.real_elements(X) & Q.invertible(X))
|
||||
assert ask(Q.real_elements(Trace(X)), Q.real_elements(X))
|
||||
assert ask(Q.integer_elements(Determinant(X)), Q.integer_elements(X))
|
||||
assert not ask(Q.integer_elements(X.I), Q.integer_elements(X))
|
||||
alpha = Symbol('alpha')
|
||||
assert ask(Q.real_elements(alpha*X), Q.real_elements(X) & Q.real(alpha))
|
||||
assert ask(Q.real_elements(LofLU(X)), Q.real_elements(X))
|
||||
e = Symbol('e', integer=True, negative=True)
|
||||
assert ask(Q.real_elements(X**e), Q.real_elements(X) & Q.invertible(X))
|
||||
assert ask(Q.real_elements(X**e), Q.real_elements(X)) is None
|
||||
|
||||
def test_matrix_element_sets():
|
||||
X = MatrixSymbol('X', 4, 4)
|
||||
assert ask(Q.real(X[1, 2]), Q.real_elements(X))
|
||||
assert ask(Q.integer(X[1, 2]), Q.integer_elements(X))
|
||||
assert ask(Q.complex(X[1, 2]), Q.complex_elements(X))
|
||||
assert ask(Q.integer_elements(Identity(3)))
|
||||
assert ask(Q.integer_elements(ZeroMatrix(3, 3)))
|
||||
assert ask(Q.integer_elements(OneMatrix(3, 3)))
|
||||
from sympy.matrices.expressions.fourier import DFT
|
||||
assert ask(Q.complex_elements(DFT(3)))
|
||||
|
||||
|
||||
def test_matrix_element_sets_slices_blocks():
|
||||
X = MatrixSymbol('X', 4, 4)
|
||||
assert ask(Q.integer_elements(X[:, 3]), Q.integer_elements(X))
|
||||
assert ask(Q.integer_elements(BlockMatrix([[X], [X]])),
|
||||
Q.integer_elements(X))
|
||||
|
||||
def test_matrix_element_sets_determinant_trace():
|
||||
assert ask(Q.integer(Determinant(X)), Q.integer_elements(X))
|
||||
assert ask(Q.integer(Trace(X)), Q.integer_elements(X))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,227 @@
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.refine import refine
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.numbers import (I, Rational, nan, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.complexes import (Abs, arg, im, re, sign)
|
||||
from sympy.functions.elementary.exponential import exp
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (atan, atan2)
|
||||
from sympy.abc import w, x, y, z
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
|
||||
|
||||
def test_Abs():
|
||||
assert refine(Abs(x), Q.positive(x)) == x
|
||||
assert refine(1 + Abs(x), Q.positive(x)) == 1 + x
|
||||
assert refine(Abs(x), Q.negative(x)) == -x
|
||||
assert refine(1 + Abs(x), Q.negative(x)) == 1 - x
|
||||
|
||||
assert refine(Abs(x**2)) != x**2
|
||||
assert refine(Abs(x**2), Q.real(x)) == x**2
|
||||
|
||||
|
||||
def test_pow1():
|
||||
assert refine((-1)**x, Q.even(x)) == 1
|
||||
assert refine((-1)**x, Q.odd(x)) == -1
|
||||
assert refine((-2)**x, Q.even(x)) == 2**x
|
||||
|
||||
# nested powers
|
||||
assert refine(sqrt(x**2)) != Abs(x)
|
||||
assert refine(sqrt(x**2), Q.complex(x)) != Abs(x)
|
||||
assert refine(sqrt(x**2), Q.real(x)) == Abs(x)
|
||||
assert refine(sqrt(x**2), Q.positive(x)) == x
|
||||
assert refine((x**3)**Rational(1, 3)) != x
|
||||
|
||||
assert refine((x**3)**Rational(1, 3), Q.real(x)) != x
|
||||
assert refine((x**3)**Rational(1, 3), Q.positive(x)) == x
|
||||
|
||||
assert refine(sqrt(1/x), Q.real(x)) != 1/sqrt(x)
|
||||
assert refine(sqrt(1/x), Q.positive(x)) == 1/sqrt(x)
|
||||
|
||||
# powers of (-1)
|
||||
assert refine((-1)**(x + y), Q.even(x)) == (-1)**y
|
||||
assert refine((-1)**(x + y + z), Q.odd(x) & Q.odd(z)) == (-1)**y
|
||||
assert refine((-1)**(x + y + 1), Q.odd(x)) == (-1)**y
|
||||
assert refine((-1)**(x + y + 2), Q.odd(x)) == (-1)**(y + 1)
|
||||
assert refine((-1)**(x + 3)) == (-1)**(x + 1)
|
||||
|
||||
# continuation
|
||||
assert refine((-1)**((-1)**x/2 - S.Half), Q.integer(x)) == (-1)**x
|
||||
assert refine((-1)**((-1)**x/2 + S.Half), Q.integer(x)) == (-1)**(x + 1)
|
||||
assert refine((-1)**((-1)**x/2 + 5*S.Half), Q.integer(x)) == (-1)**(x + 1)
|
||||
|
||||
|
||||
def test_pow2():
|
||||
assert refine((-1)**((-1)**x/2 - 7*S.Half), Q.integer(x)) == (-1)**(x + 1)
|
||||
assert refine((-1)**((-1)**x/2 - 9*S.Half), Q.integer(x)) == (-1)**x
|
||||
|
||||
# powers of Abs
|
||||
assert refine(Abs(x)**2, Q.real(x)) == x**2
|
||||
assert refine(Abs(x)**3, Q.real(x)) == Abs(x)**3
|
||||
assert refine(Abs(x)**2) == Abs(x)**2
|
||||
|
||||
|
||||
def test_exp():
|
||||
x = Symbol('x', integer=True)
|
||||
assert refine(exp(pi*I*2*x)) == 1
|
||||
assert refine(exp(pi*I*2*(x + S.Half))) == -1
|
||||
assert refine(exp(pi*I*2*(x + Rational(1, 4)))) == I
|
||||
assert refine(exp(pi*I*2*(x + Rational(3, 4)))) == -I
|
||||
|
||||
|
||||
def test_Piecewise():
|
||||
assert refine(Piecewise((1, x < 0), (3, True)), (x < 0)) == 1
|
||||
assert refine(Piecewise((1, x < 0), (3, True)), ~(x < 0)) == 3
|
||||
assert refine(Piecewise((1, x < 0), (3, True)), (y < 0)) == \
|
||||
Piecewise((1, x < 0), (3, True))
|
||||
assert refine(Piecewise((1, x > 0), (3, True)), (x > 0)) == 1
|
||||
assert refine(Piecewise((1, x > 0), (3, True)), ~(x > 0)) == 3
|
||||
assert refine(Piecewise((1, x > 0), (3, True)), (y > 0)) == \
|
||||
Piecewise((1, x > 0), (3, True))
|
||||
assert refine(Piecewise((1, x <= 0), (3, True)), (x <= 0)) == 1
|
||||
assert refine(Piecewise((1, x <= 0), (3, True)), ~(x <= 0)) == 3
|
||||
assert refine(Piecewise((1, x <= 0), (3, True)), (y <= 0)) == \
|
||||
Piecewise((1, x <= 0), (3, True))
|
||||
assert refine(Piecewise((1, x >= 0), (3, True)), (x >= 0)) == 1
|
||||
assert refine(Piecewise((1, x >= 0), (3, True)), ~(x >= 0)) == 3
|
||||
assert refine(Piecewise((1, x >= 0), (3, True)), (y >= 0)) == \
|
||||
Piecewise((1, x >= 0), (3, True))
|
||||
assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(x, 0)))\
|
||||
== 1
|
||||
assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(0, x)))\
|
||||
== 1
|
||||
assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(x, 0)))\
|
||||
== 3
|
||||
assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(0, x)))\
|
||||
== 3
|
||||
assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(y, 0)))\
|
||||
== Piecewise((1, Eq(x, 0)), (3, True))
|
||||
assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(x, 0)))\
|
||||
== 1
|
||||
assert refine(Piecewise((1, Ne(x, 0)), (3, True)), ~(Ne(x, 0)))\
|
||||
== 3
|
||||
assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(y, 0)))\
|
||||
== Piecewise((1, Ne(x, 0)), (3, True))
|
||||
|
||||
|
||||
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_re():
|
||||
assert refine(re(x), Q.real(x)) == x
|
||||
assert refine(re(x), Q.imaginary(x)) is S.Zero
|
||||
assert refine(re(x+y), Q.real(x) & Q.real(y)) == x + y
|
||||
assert refine(re(x+y), Q.real(x) & Q.imaginary(y)) == x
|
||||
assert refine(re(x*y), Q.real(x) & Q.real(y)) == x * y
|
||||
assert refine(re(x*y), Q.real(x) & Q.imaginary(y)) == 0
|
||||
assert refine(re(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) == x * y * z
|
||||
|
||||
|
||||
def test_im():
|
||||
assert refine(im(x), Q.imaginary(x)) == -I*x
|
||||
assert refine(im(x), Q.real(x)) is S.Zero
|
||||
assert refine(im(x+y), Q.imaginary(x) & Q.imaginary(y)) == -I*x - I*y
|
||||
assert refine(im(x+y), Q.real(x) & Q.imaginary(y)) == -I*y
|
||||
assert refine(im(x*y), Q.imaginary(x) & Q.real(y)) == -I*x*y
|
||||
assert refine(im(x*y), Q.imaginary(x) & Q.imaginary(y)) == 0
|
||||
assert refine(im(1/x), Q.imaginary(x)) == -I/x
|
||||
assert refine(im(x*y*z), Q.imaginary(x) & Q.imaginary(y)
|
||||
& Q.imaginary(z)) == -I*x*y*z
|
||||
|
||||
|
||||
def test_complex():
|
||||
assert refine(re(1/(x + I*y)), Q.real(x) & Q.real(y)) == \
|
||||
x/(x**2 + y**2)
|
||||
assert refine(im(1/(x + I*y)), Q.real(x) & Q.real(y)) == \
|
||||
-y/(x**2 + y**2)
|
||||
assert refine(re((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y)
|
||||
& Q.real(z)) == w*y - x*z
|
||||
assert refine(im((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y)
|
||||
& Q.real(z)) == w*z + x*y
|
||||
|
||||
|
||||
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_arg():
|
||||
x = Symbol('x', complex = True)
|
||||
assert refine(arg(x), Q.positive(x)) == 0
|
||||
assert refine(arg(x), Q.negative(x)) == pi
|
||||
|
||||
def test_func_args():
|
||||
class MyClass(Expr):
|
||||
# A class with nontrivial .func
|
||||
|
||||
def __init__(self, *args):
|
||||
self.my_member = ""
|
||||
|
||||
@property
|
||||
def func(self):
|
||||
def my_func(*args):
|
||||
obj = MyClass(*args)
|
||||
obj.my_member = self.my_member
|
||||
return obj
|
||||
return my_func
|
||||
|
||||
x = MyClass()
|
||||
x.my_member = "A very important value"
|
||||
assert x.my_member == refine(x).my_member
|
||||
|
||||
def test_issue_refine_9384():
|
||||
assert refine(Piecewise((1, x < 0), (0, True)), Q.positive(x)) == 0
|
||||
assert refine(Piecewise((1, x < 0), (0, True)), Q.negative(x)) == 1
|
||||
assert refine(Piecewise((1, x > 0), (0, True)), Q.positive(x)) == 1
|
||||
assert refine(Piecewise((1, x > 0), (0, True)), Q.negative(x)) == 0
|
||||
|
||||
|
||||
def test_eval_refine():
|
||||
class MockExpr(Expr):
|
||||
def _eval_refine(self, assumptions):
|
||||
return True
|
||||
|
||||
mock_obj = MockExpr()
|
||||
assert refine(mock_obj)
|
||||
|
||||
def test_refine_issue_12724():
|
||||
expr1 = refine(Abs(x * y), Q.positive(x))
|
||||
expr2 = refine(Abs(x * y * z), Q.positive(x))
|
||||
assert expr1 == x * Abs(y)
|
||||
assert expr2 == x * Abs(y * z)
|
||||
y1 = Symbol('y1', real = True)
|
||||
expr3 = refine(Abs(x * y1**2 * z), Q.positive(x))
|
||||
assert expr3 == x * y1**2 * Abs(z)
|
||||
|
||||
|
||||
def test_matrixelement():
|
||||
x = MatrixSymbol('x', 3, 3)
|
||||
i = Symbol('i', positive = True)
|
||||
j = Symbol('j', positive = True)
|
||||
assert refine(x[0, 1], Q.symmetric(x)) == x[0, 1]
|
||||
assert refine(x[1, 0], Q.symmetric(x)) == x[0, 1]
|
||||
assert refine(x[i, j], Q.symmetric(x)) == x[j, i]
|
||||
assert refine(x[j, i], Q.symmetric(x)) == x[j, i]
|
||||
@@ -0,0 +1,172 @@
|
||||
from sympy.assumptions.lra_satask import lra_satask
|
||||
from sympy.logic.algorithms.lra_theory import UnhandledInput
|
||||
from sympy.assumptions.ask import Q, ask
|
||||
|
||||
from sympy.core import symbols, Symbol
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.core.numbers import I
|
||||
|
||||
from sympy.testing.pytest import raises, XFAIL
|
||||
x, y, z = symbols("x y z", real=True)
|
||||
|
||||
def test_lra_satask():
|
||||
im = Symbol('im', imaginary=True)
|
||||
|
||||
# test preprocessing of unequalities is working correctly
|
||||
assert lra_satask(Q.eq(x, 1), ~Q.ne(x, 0)) is False
|
||||
assert lra_satask(Q.eq(x, 0), ~Q.ne(x, 0)) is True
|
||||
assert lra_satask(~Q.ne(x, 0), Q.eq(x, 0)) is True
|
||||
assert lra_satask(~Q.eq(x, 0), Q.eq(x, 0)) is False
|
||||
assert lra_satask(Q.ne(x, 0), Q.eq(x, 0)) is False
|
||||
|
||||
# basic tests
|
||||
assert lra_satask(Q.ne(x, x)) is False
|
||||
assert lra_satask(Q.eq(x, x)) is True
|
||||
assert lra_satask(Q.gt(x, 0), Q.gt(x, 1)) is True
|
||||
|
||||
# check that True/False are handled
|
||||
assert lra_satask(Q.gt(x, 0), True) is None
|
||||
assert raises(ValueError, lambda: lra_satask(Q.gt(x, 0), False))
|
||||
|
||||
# check imaginary numbers are correctly handled
|
||||
# (im * I).is_real returns True so this is an edge case
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.gt(im * I, 0), Q.gt(im * I, 0)))
|
||||
|
||||
# check matrix inputs
|
||||
X = MatrixSymbol("X", 2, 2)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(X, 2) & Q.gt(X, 3)))
|
||||
|
||||
|
||||
def test_old_assumptions():
|
||||
# test unhandled old assumptions
|
||||
w = symbols("w")
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", rational=False, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", odd=True, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", even=True, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", prime=True, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", composite=True, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", integer=True, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
w = symbols("w", integer=False, real=True)
|
||||
raises(UnhandledInput, lambda: lra_satask(Q.lt(w, 2) & Q.gt(w, 3)))
|
||||
|
||||
# test handled
|
||||
w = symbols("w", positive=True, real=True)
|
||||
assert lra_satask(Q.le(w, 0)) is False
|
||||
assert lra_satask(Q.gt(w, 0)) is True
|
||||
w = symbols("w", negative=True, real=True)
|
||||
assert lra_satask(Q.lt(w, 0)) is True
|
||||
assert lra_satask(Q.ge(w, 0)) is False
|
||||
w = symbols("w", zero=True, real=True)
|
||||
assert lra_satask(Q.eq(w, 0)) is True
|
||||
assert lra_satask(Q.ne(w, 0)) is False
|
||||
w = symbols("w", nonzero=True, real=True)
|
||||
assert lra_satask(Q.ne(w, 0)) is True
|
||||
assert lra_satask(Q.eq(w, 1)) is None
|
||||
w = symbols("w", nonpositive=True, real=True)
|
||||
assert lra_satask(Q.le(w, 0)) is True
|
||||
assert lra_satask(Q.gt(w, 0)) is False
|
||||
w = symbols("w", nonnegative=True, real=True)
|
||||
assert lra_satask(Q.ge(w, 0)) is True
|
||||
assert lra_satask(Q.lt(w, 0)) is False
|
||||
|
||||
|
||||
def test_rel_queries():
|
||||
assert ask(Q.lt(x, 2) & Q.gt(x, 3)) is False
|
||||
assert ask(Q.positive(x - z), (x > y) & (y > z)) is True
|
||||
assert ask(x + y > 2, (x < 0) & (y <0)) is False
|
||||
assert ask(x > z, (x > y) & (y > z)) is True
|
||||
|
||||
|
||||
def test_unhandled_queries():
|
||||
X = MatrixSymbol("X", 2, 2)
|
||||
assert ask(Q.lt(X, 2) & Q.gt(X, 3)) is None
|
||||
|
||||
|
||||
def test_all_pred():
|
||||
# test usable pred
|
||||
assert lra_satask(Q.extended_positive(x), (x > 2)) is True
|
||||
assert lra_satask(Q.positive_infinite(x)) is False
|
||||
assert lra_satask(Q.negative_infinite(x)) is False
|
||||
|
||||
# test disallowed pred
|
||||
raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.prime(x)))
|
||||
raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.composite(x)))
|
||||
raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.odd(x)))
|
||||
raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.even(x)))
|
||||
raises(UnhandledInput, lambda: lra_satask((x > 0), (x > 2) & Q.integer(x)))
|
||||
|
||||
|
||||
def test_number_line_properties():
|
||||
# From:
|
||||
# https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
|
||||
|
||||
a, b, c = symbols("a b c", real=True)
|
||||
|
||||
# Transitivity
|
||||
# If a <= b and b <= c, then a <= c.
|
||||
assert ask(a <= c, (a <= b) & (b <= c)) is True
|
||||
# If a <= b and b < c, then a < c.
|
||||
assert ask(a < c, (a <= b) & (b < c)) is True
|
||||
# If a < b and b <= c, then a < c.
|
||||
assert ask(a < c, (a < b) & (b <= c)) is True
|
||||
|
||||
# Addition and subtraction
|
||||
# If a <= b, then a + c <= b + c and a - c <= b - c.
|
||||
assert ask(a + c <= b + c, a <= b) is True
|
||||
assert ask(a - c <= b - c, a <= b) is True
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_failing_number_line_properties():
|
||||
# From:
|
||||
# https://en.wikipedia.org/wiki/Inequality_(mathematics)#Properties_on_the_number_line
|
||||
|
||||
a, b, c = symbols("a b c", real=True)
|
||||
|
||||
# Multiplication and division
|
||||
# If a <= b and c > 0, then ac <= bc and a/c <= b/c. (True for non-zero c)
|
||||
assert ask(a*c <= b*c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
|
||||
assert ask(a/c <= b/c, (a <= b) & (c > 0) & ~ Q.zero(c)) is True
|
||||
# If a <= b and c < 0, then ac >= bc and a/c >= b/c. (True for non-zero c)
|
||||
assert ask(a*c >= b*c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
|
||||
assert ask(a/c >= b/c, (a <= b) & (c < 0) & ~ Q.zero(c)) is True
|
||||
|
||||
# Additive inverse
|
||||
# If a <= b, then -a >= -b.
|
||||
assert ask(-a >= -b, a <= b) is True
|
||||
|
||||
# Multiplicative inverse
|
||||
# For a, b that are both negative or both positive:
|
||||
# If a <= b, then 1/a >= 1/b .
|
||||
assert ask(1/a >= 1/b, (a <= b) & Q.positive(x) & Q.positive(b)) is True
|
||||
assert ask(1/a >= 1/b, (a <= b) & Q.negative(x) & Q.negative(b)) is True
|
||||
|
||||
|
||||
def test_equality():
|
||||
# test symmetry and reflexivity
|
||||
assert ask(Q.eq(x, x)) is True
|
||||
assert ask(Q.eq(y, x), Q.eq(x, y)) is True
|
||||
assert ask(Q.eq(y, x), ~Q.eq(z, z) | Q.eq(x, y)) is True
|
||||
|
||||
# test transitivity
|
||||
assert ask(Q.eq(x,z), Q.eq(x,y) & Q.eq(y,z)) is True
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_equality_failing():
|
||||
# Note that implementing the substitution property of equality
|
||||
# most likely requires a redesign of the new assumptions.
|
||||
# See issue #25485 for why this is the case and general ideas
|
||||
# about how things could be redesigned.
|
||||
|
||||
# test substitution property
|
||||
assert ask(Q.prime(x), Q.eq(x, y) & Q.prime(y)) is True
|
||||
assert ask(Q.real(x), Q.eq(x, y) & Q.real(y)) is True
|
||||
assert ask(Q.imaginary(x), Q.eq(x, y) & Q.imaginary(y)) is True
|
||||
@@ -0,0 +1,378 @@
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.assume import assuming
|
||||
from sympy.core.numbers import (I, pi)
|
||||
from sympy.core.relational import (Eq, Gt)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.logic.boolalg import Implies
|
||||
from sympy.matrices.expressions.matexpr import MatrixSymbol
|
||||
from sympy.assumptions.cnf import CNF, Literal
|
||||
from sympy.assumptions.satask import (satask, extract_predargs,
|
||||
get_relevant_clsfacts)
|
||||
|
||||
from sympy.testing.pytest import raises, XFAIL
|
||||
|
||||
|
||||
x, y, z = symbols('x y z')
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
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 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_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
|
||||
|
||||
|
||||
@XFAIL
|
||||
# Requires correct Q.square calculation first
|
||||
def test_invertible():
|
||||
A = MatrixSymbol('A', 5, 5)
|
||||
B = MatrixSymbol('B', 5, 5)
|
||||
assert satask(Q.invertible(A*B), Q.invertible(A) & Q.invertible(B)) is True
|
||||
assert satask(Q.invertible(A), Q.invertible(A*B)) is True
|
||||
assert satask(Q.invertible(A) & Q.invertible(B), Q.invertible(A*B)) is True
|
||||
|
||||
|
||||
def test_prime():
|
||||
assert satask(Q.prime(5)) is True
|
||||
assert satask(Q.prime(6)) is False
|
||||
assert satask(Q.prime(-5)) is False
|
||||
|
||||
assert satask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None
|
||||
assert satask(Q.prime(x*y), Q.prime(x) & Q.prime(y)) is False
|
||||
|
||||
|
||||
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_rational_irrational():
|
||||
assert satask(Q.irrational(2)) is False
|
||||
assert satask(Q.rational(2)) is True
|
||||
assert satask(Q.irrational(pi)) is True
|
||||
assert satask(Q.rational(pi)) is False
|
||||
assert satask(Q.irrational(I)) is False
|
||||
assert satask(Q.rational(I)) is False
|
||||
|
||||
assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.irrational(y) &
|
||||
Q.rational(z)) is None
|
||||
assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is True
|
||||
assert satask(Q.irrational(pi*x*y), Q.rational(x) & Q.rational(y)) is True
|
||||
|
||||
assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.irrational(y) &
|
||||
Q.rational(z)) is None
|
||||
assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is True
|
||||
assert satask(Q.irrational(pi + x + y), Q.rational(x) & Q.rational(y)) is True
|
||||
|
||||
assert satask(Q.irrational(x*y*z), Q.rational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is False
|
||||
assert satask(Q.rational(x*y*z), Q.rational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is True
|
||||
|
||||
assert satask(Q.irrational(x + y + z), Q.rational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is False
|
||||
assert satask(Q.rational(x + y + z), Q.rational(x) & Q.rational(y) &
|
||||
Q.rational(z)) is True
|
||||
|
||||
|
||||
def test_even_satask():
|
||||
assert satask(Q.even(2)) is True
|
||||
assert satask(Q.even(3)) is False
|
||||
|
||||
assert satask(Q.even(x*y), Q.even(x) & Q.odd(y)) is True
|
||||
assert satask(Q.even(x*y), Q.even(x) & Q.integer(y)) is True
|
||||
assert satask(Q.even(x*y), Q.even(x) & Q.even(y)) is True
|
||||
assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
|
||||
assert satask(Q.even(x*y), Q.even(x)) is None
|
||||
assert satask(Q.even(x*y), Q.odd(x) & Q.integer(y)) is None
|
||||
assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False
|
||||
|
||||
assert satask(Q.even(abs(x)), Q.even(x)) is True
|
||||
assert satask(Q.even(abs(x)), Q.odd(x)) is False
|
||||
assert satask(Q.even(x), Q.even(abs(x))) is None # x could be complex
|
||||
|
||||
|
||||
def test_odd_satask():
|
||||
assert satask(Q.odd(2)) is False
|
||||
assert satask(Q.odd(3)) is True
|
||||
|
||||
assert satask(Q.odd(x*y), Q.even(x) & Q.odd(y)) is False
|
||||
assert satask(Q.odd(x*y), Q.even(x) & Q.integer(y)) is False
|
||||
assert satask(Q.odd(x*y), Q.even(x) & Q.even(y)) is False
|
||||
assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
|
||||
assert satask(Q.odd(x*y), Q.even(x)) is None
|
||||
assert satask(Q.odd(x*y), Q.odd(x) & Q.integer(y)) is None
|
||||
assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True
|
||||
|
||||
assert satask(Q.odd(abs(x)), Q.even(x)) is False
|
||||
assert satask(Q.odd(abs(x)), Q.odd(x)) is True
|
||||
assert satask(Q.odd(x), Q.odd(abs(x))) is None # x could be complex
|
||||
|
||||
|
||||
def test_integer():
|
||||
assert satask(Q.integer(1)) is True
|
||||
assert satask(Q.integer(S.Half)) is False
|
||||
|
||||
assert satask(Q.integer(x + y), Q.integer(x) & Q.integer(y)) is True
|
||||
assert satask(Q.integer(x + y), Q.integer(x)) is None
|
||||
|
||||
assert satask(Q.integer(x + y), Q.integer(x) & ~Q.integer(y)) is False
|
||||
assert satask(Q.integer(x + y + z), Q.integer(x) & Q.integer(y) &
|
||||
~Q.integer(z)) is False
|
||||
assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y) &
|
||||
~Q.integer(z)) is None
|
||||
assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y)) is None
|
||||
assert satask(Q.integer(x + y), Q.integer(x) & Q.irrational(y)) is False
|
||||
|
||||
assert satask(Q.integer(x*y), Q.integer(x) & Q.integer(y)) is True
|
||||
assert satask(Q.integer(x*y), Q.integer(x)) is None
|
||||
|
||||
assert satask(Q.integer(x*y), Q.integer(x) & ~Q.integer(y)) is None
|
||||
assert satask(Q.integer(x*y), Q.integer(x) & ~Q.rational(y)) is False
|
||||
assert satask(Q.integer(x*y*z), Q.integer(x) & Q.integer(y) &
|
||||
~Q.rational(z)) is False
|
||||
assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y) &
|
||||
~Q.rational(z)) is None
|
||||
assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y)) is None
|
||||
assert satask(Q.integer(x*y), Q.integer(x) & Q.irrational(y)) is False
|
||||
|
||||
|
||||
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_imaginary():
|
||||
assert satask(Q.imaginary(2*I)) is True
|
||||
assert satask(Q.imaginary(x*y), Q.imaginary(x)) is None
|
||||
assert satask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True
|
||||
assert satask(Q.imaginary(x), Q.real(x)) is False
|
||||
assert satask(Q.imaginary(1)) is False
|
||||
assert satask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False
|
||||
assert satask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False
|
||||
|
||||
|
||||
def test_real():
|
||||
assert satask(Q.real(x*y), Q.real(x) & Q.real(y)) is True
|
||||
assert satask(Q.real(x + y), Q.real(x) & Q.real(y)) is True
|
||||
assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) is True
|
||||
assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y)) is None
|
||||
assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is False
|
||||
assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True
|
||||
assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y)) is None
|
||||
|
||||
|
||||
def test_pos_neg():
|
||||
assert satask(~Q.positive(x), Q.negative(x)) is True
|
||||
assert satask(~Q.negative(x), Q.positive(x)) is True
|
||||
assert satask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True
|
||||
assert satask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True
|
||||
assert satask(Q.positive(x + y), Q.negative(x) & Q.negative(y)) is False
|
||||
assert satask(Q.negative(x + y), Q.positive(x) & Q.positive(y)) is False
|
||||
|
||||
|
||||
def test_pow_pos_neg():
|
||||
assert satask(Q.nonnegative(x**2), Q.positive(x)) is True
|
||||
assert satask(Q.nonpositive(x**2), Q.positive(x)) is False
|
||||
assert satask(Q.positive(x**2), Q.positive(x)) is True
|
||||
assert satask(Q.negative(x**2), Q.positive(x)) is False
|
||||
assert satask(Q.real(x**2), Q.positive(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**2), Q.negative(x)) is True
|
||||
assert satask(Q.nonpositive(x**2), Q.negative(x)) is False
|
||||
assert satask(Q.positive(x**2), Q.negative(x)) is True
|
||||
assert satask(Q.negative(x**2), Q.negative(x)) is False
|
||||
assert satask(Q.real(x**2), Q.negative(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**2), Q.nonnegative(x)) is True
|
||||
assert satask(Q.nonpositive(x**2), Q.nonnegative(x)) is None
|
||||
assert satask(Q.positive(x**2), Q.nonnegative(x)) is None
|
||||
assert satask(Q.negative(x**2), Q.nonnegative(x)) is False
|
||||
assert satask(Q.real(x**2), Q.nonnegative(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**2), Q.nonpositive(x)) is True
|
||||
assert satask(Q.nonpositive(x**2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.positive(x**2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.negative(x**2), Q.nonpositive(x)) is False
|
||||
assert satask(Q.real(x**2), Q.nonpositive(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**3), Q.positive(x)) is True
|
||||
assert satask(Q.nonpositive(x**3), Q.positive(x)) is False
|
||||
assert satask(Q.positive(x**3), Q.positive(x)) is True
|
||||
assert satask(Q.negative(x**3), Q.positive(x)) is False
|
||||
assert satask(Q.real(x**3), Q.positive(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**3), Q.negative(x)) is False
|
||||
assert satask(Q.nonpositive(x**3), Q.negative(x)) is True
|
||||
assert satask(Q.positive(x**3), Q.negative(x)) is False
|
||||
assert satask(Q.negative(x**3), Q.negative(x)) is True
|
||||
assert satask(Q.real(x**3), Q.negative(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**3), Q.nonnegative(x)) is True
|
||||
assert satask(Q.nonpositive(x**3), Q.nonnegative(x)) is None
|
||||
assert satask(Q.positive(x**3), Q.nonnegative(x)) is None
|
||||
assert satask(Q.negative(x**3), Q.nonnegative(x)) is False
|
||||
assert satask(Q.real(x**3), Q.nonnegative(x)) is True
|
||||
|
||||
assert satask(Q.nonnegative(x**3), Q.nonpositive(x)) is None
|
||||
assert satask(Q.nonpositive(x**3), Q.nonpositive(x)) is True
|
||||
assert satask(Q.positive(x**3), Q.nonpositive(x)) is False
|
||||
assert satask(Q.negative(x**3), Q.nonpositive(x)) is None
|
||||
assert satask(Q.real(x**3), Q.nonpositive(x)) is True
|
||||
|
||||
# If x is zero, x**negative is not real.
|
||||
assert satask(Q.nonnegative(x**-2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.nonpositive(x**-2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.positive(x**-2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.negative(x**-2), Q.nonpositive(x)) is None
|
||||
assert satask(Q.real(x**-2), Q.nonpositive(x)) is None
|
||||
|
||||
# We could deduce things for negative powers if x is nonzero, but it
|
||||
# isn't implemented yet.
|
||||
|
||||
|
||||
def test_prime_composite():
|
||||
assert satask(Q.prime(x), Q.composite(x)) is False
|
||||
assert satask(Q.composite(x), Q.prime(x)) is False
|
||||
assert satask(Q.composite(x), ~Q.prime(x)) is None
|
||||
assert satask(Q.prime(x), ~Q.composite(x)) is None
|
||||
# since 1 is neither prime nor composite the following should hold
|
||||
assert satask(Q.prime(x), Q.integer(x) & Q.positive(x) & ~Q.composite(x)) is None
|
||||
assert satask(Q.prime(2)) is True
|
||||
assert satask(Q.prime(4)) is False
|
||||
assert satask(Q.prime(1)) is False
|
||||
assert satask(Q.composite(1)) is False
|
||||
|
||||
|
||||
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_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)})}
|
||||
@@ -0,0 +1,50 @@
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.logic.boolalg import (And, Or)
|
||||
|
||||
from sympy.assumptions.sathandlers import (ClassFactRegistry, allargs,
|
||||
anyarg, exactlyonearg,)
|
||||
|
||||
x, y, z = symbols('x y z')
|
||||
|
||||
|
||||
def test_class_handler_registry():
|
||||
my_handler_registry = ClassFactRegistry()
|
||||
|
||||
# The predicate doesn't matter here, so just pass
|
||||
@my_handler_registry.register(Mul)
|
||||
def fact1(expr):
|
||||
pass
|
||||
@my_handler_registry.multiregister(Expr)
|
||||
def fact2(expr):
|
||||
pass
|
||||
|
||||
assert my_handler_registry[Basic] == (frozenset(), frozenset())
|
||||
assert my_handler_registry[Expr] == (frozenset(), frozenset({fact2}))
|
||||
assert my_handler_registry[Mul] == (frozenset({fact1}), frozenset({fact2}))
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
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_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)))
|
||||
@@ -0,0 +1,39 @@
|
||||
from sympy.assumptions.ask import Q
|
||||
from sympy.assumptions.wrapper import (AssumptionsWrapper, is_infinite,
|
||||
is_extended_real)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.core.assumptions import _assume_defined
|
||||
|
||||
|
||||
def test_all_predicates():
|
||||
for fact in _assume_defined:
|
||||
method_name = f'_eval_is_{fact}'
|
||||
assert hasattr(AssumptionsWrapper, method_name)
|
||||
|
||||
|
||||
def test_AssumptionsWrapper():
|
||||
x = Symbol('x', positive=True)
|
||||
y = Symbol('y')
|
||||
assert AssumptionsWrapper(x).is_positive
|
||||
assert AssumptionsWrapper(y).is_positive is None
|
||||
assert AssumptionsWrapper(y, Q.positive(y)).is_positive
|
||||
|
||||
|
||||
def test_is_infinite():
|
||||
x = Symbol('x', infinite=True)
|
||||
y = Symbol('y', infinite=False)
|
||||
z = Symbol('z')
|
||||
assert is_infinite(x)
|
||||
assert not is_infinite(y)
|
||||
assert is_infinite(z) is None
|
||||
assert is_infinite(z, Q.infinite(z))
|
||||
|
||||
|
||||
def test_is_extended_real():
|
||||
x = Symbol('x', extended_real=True)
|
||||
y = Symbol('y', extended_real=False)
|
||||
z = Symbol('z')
|
||||
assert is_extended_real(x)
|
||||
assert not is_extended_real(y)
|
||||
assert is_extended_real(z) is None
|
||||
assert is_extended_real(z, Q.extended_real(z))
|
||||
Reference in New Issue
Block a user