diff --git a/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2636b8cf30d5640a4a125f1783af8a82891ae0b Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3ba9a0da1a9983a27b16a88562a72027953cfeb Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/abc.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..215e0e802010423af5b8c032206b80eafa6ad9d5 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/conftest.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05199d0c18bdce529c61d60960db43ce2ef9631f Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/galgebra.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d52e844cffad8303d51f429d6efec30148b545f7 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/release.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc b/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49a6c50dda97ab8737b9eaa3c40631a2a5e34c3b Binary files /dev/null and b/lib/python3.12/site-packages/sympy/__pycache__/this.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/__init__.py b/lib/python3.12/site-packages/sympy/assumptions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..af862653f3ce0eeb67f7764e16c32f3466e87024 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/__init__.py @@ -0,0 +1,18 @@ +""" +A module to implement logical predicates and assumption system. +""" + +from .assume import ( + AppliedPredicate, Predicate, AssumptionsContext, assuming, + global_assumptions +) +from .ask import Q, ask, register_handler, remove_handler +from .refine import refine +from .relation import BinaryRelation, AppliedBinaryRelation + +__all__ = [ + 'AppliedPredicate', 'Predicate', 'AssumptionsContext', 'assuming', + 'global_assumptions', 'Q', 'ask', 'register_handler', 'remove_handler', + 'refine', + 'BinaryRelation', 'AppliedBinaryRelation' +] diff --git a/lib/python3.12/site-packages/sympy/assumptions/ask.py b/lib/python3.12/site-packages/sympy/assumptions/ask.py new file mode 100644 index 0000000000000000000000000000000000000000..205850932de0a4db01bfd68679c7af25e9db8690 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/ask.py @@ -0,0 +1,651 @@ +"""Module for querying SymPy objects about assumptions.""" + +from sympy.assumptions.assume import (global_assumptions, Predicate, + AppliedPredicate) +from sympy.assumptions.cnf import CNF, EncodedCNF, Literal +from sympy.core import sympify +from sympy.core.kind import BooleanKind +from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le +from sympy.logic.inference import satisfiable +from sympy.utilities.decorator import memoize_property +from sympy.utilities.exceptions import (sympy_deprecation_warning, + SymPyDeprecationWarning, + ignore_warnings) + + +# Memoization is necessary for the properties of AssumptionKeys to +# ensure that only one object of Predicate objects are created. +# This is because assumption handlers are registered on those objects. + + +class AssumptionKeys: + """ + This class contains all the supported keys by ``ask``. + It should be accessed via the instance ``sympy.Q``. + + """ + + # DO NOT add methods or properties other than predicate keys. + # SAT solver checks the properties of Q and use them to compute the + # fact system. Non-predicate attributes will break this. + + @memoize_property + def hermitian(self): + from .handlers.sets import HermitianPredicate + return HermitianPredicate() + + @memoize_property + def antihermitian(self): + from .handlers.sets import AntihermitianPredicate + return AntihermitianPredicate() + + @memoize_property + def real(self): + from .handlers.sets import RealPredicate + return RealPredicate() + + @memoize_property + def extended_real(self): + from .handlers.sets import ExtendedRealPredicate + return ExtendedRealPredicate() + + @memoize_property + def imaginary(self): + from .handlers.sets import ImaginaryPredicate + return ImaginaryPredicate() + + @memoize_property + def complex(self): + from .handlers.sets import ComplexPredicate + return ComplexPredicate() + + @memoize_property + def algebraic(self): + from .handlers.sets import AlgebraicPredicate + return AlgebraicPredicate() + + @memoize_property + def transcendental(self): + from .predicates.sets import TranscendentalPredicate + return TranscendentalPredicate() + + @memoize_property + def integer(self): + from .handlers.sets import IntegerPredicate + return IntegerPredicate() + + @memoize_property + def noninteger(self): + from .predicates.sets import NonIntegerPredicate + return NonIntegerPredicate() + + @memoize_property + def rational(self): + from .handlers.sets import RationalPredicate + return RationalPredicate() + + @memoize_property + def irrational(self): + from .handlers.sets import IrrationalPredicate + return IrrationalPredicate() + + @memoize_property + def finite(self): + from .handlers.calculus import FinitePredicate + return FinitePredicate() + + @memoize_property + def infinite(self): + from .handlers.calculus import InfinitePredicate + return InfinitePredicate() + + @memoize_property + def positive_infinite(self): + from .handlers.calculus import PositiveInfinitePredicate + return PositiveInfinitePredicate() + + @memoize_property + def negative_infinite(self): + from .handlers.calculus import NegativeInfinitePredicate + return NegativeInfinitePredicate() + + @memoize_property + def positive(self): + from .handlers.order import PositivePredicate + return PositivePredicate() + + @memoize_property + def negative(self): + from .handlers.order import NegativePredicate + return NegativePredicate() + + @memoize_property + def zero(self): + from .handlers.order import ZeroPredicate + return ZeroPredicate() + + @memoize_property + def extended_positive(self): + from .handlers.order import ExtendedPositivePredicate + return ExtendedPositivePredicate() + + @memoize_property + def extended_negative(self): + from .handlers.order import ExtendedNegativePredicate + return ExtendedNegativePredicate() + + @memoize_property + def nonzero(self): + from .handlers.order import NonZeroPredicate + return NonZeroPredicate() + + @memoize_property + def nonpositive(self): + from .handlers.order import NonPositivePredicate + return NonPositivePredicate() + + @memoize_property + def nonnegative(self): + from .handlers.order import NonNegativePredicate + return NonNegativePredicate() + + @memoize_property + def extended_nonzero(self): + from .handlers.order import ExtendedNonZeroPredicate + return ExtendedNonZeroPredicate() + + @memoize_property + def extended_nonpositive(self): + from .handlers.order import ExtendedNonPositivePredicate + return ExtendedNonPositivePredicate() + + @memoize_property + def extended_nonnegative(self): + from .handlers.order import ExtendedNonNegativePredicate + return ExtendedNonNegativePredicate() + + @memoize_property + def even(self): + from .handlers.ntheory import EvenPredicate + return EvenPredicate() + + @memoize_property + def odd(self): + from .handlers.ntheory import OddPredicate + return OddPredicate() + + @memoize_property + def prime(self): + from .handlers.ntheory import PrimePredicate + return PrimePredicate() + + @memoize_property + def composite(self): + from .handlers.ntheory import CompositePredicate + return CompositePredicate() + + @memoize_property + def commutative(self): + from .handlers.common import CommutativePredicate + return CommutativePredicate() + + @memoize_property + def is_true(self): + from .handlers.common import IsTruePredicate + return IsTruePredicate() + + @memoize_property + def symmetric(self): + from .handlers.matrices import SymmetricPredicate + return SymmetricPredicate() + + @memoize_property + def invertible(self): + from .handlers.matrices import InvertiblePredicate + return InvertiblePredicate() + + @memoize_property + def orthogonal(self): + from .handlers.matrices import OrthogonalPredicate + return OrthogonalPredicate() + + @memoize_property + def unitary(self): + from .handlers.matrices import UnitaryPredicate + return UnitaryPredicate() + + @memoize_property + def positive_definite(self): + from .handlers.matrices import PositiveDefinitePredicate + return PositiveDefinitePredicate() + + @memoize_property + def upper_triangular(self): + from .handlers.matrices import UpperTriangularPredicate + return UpperTriangularPredicate() + + @memoize_property + def lower_triangular(self): + from .handlers.matrices import LowerTriangularPredicate + return LowerTriangularPredicate() + + @memoize_property + def diagonal(self): + from .handlers.matrices import DiagonalPredicate + return DiagonalPredicate() + + @memoize_property + def fullrank(self): + from .handlers.matrices import FullRankPredicate + return FullRankPredicate() + + @memoize_property + def square(self): + from .handlers.matrices import SquarePredicate + return SquarePredicate() + + @memoize_property + def integer_elements(self): + from .handlers.matrices import IntegerElementsPredicate + return IntegerElementsPredicate() + + @memoize_property + def real_elements(self): + from .handlers.matrices import RealElementsPredicate + return RealElementsPredicate() + + @memoize_property + def complex_elements(self): + from .handlers.matrices import ComplexElementsPredicate + return ComplexElementsPredicate() + + @memoize_property + def singular(self): + from .predicates.matrices import SingularPredicate + return SingularPredicate() + + @memoize_property + def normal(self): + from .predicates.matrices import NormalPredicate + return NormalPredicate() + + @memoize_property + def triangular(self): + from .predicates.matrices import TriangularPredicate + return TriangularPredicate() + + @memoize_property + def unit_triangular(self): + from .predicates.matrices import UnitTriangularPredicate + return UnitTriangularPredicate() + + @memoize_property + def eq(self): + from .relation.equality import EqualityPredicate + return EqualityPredicate() + + @memoize_property + def ne(self): + from .relation.equality import UnequalityPredicate + return UnequalityPredicate() + + @memoize_property + def gt(self): + from .relation.equality import StrictGreaterThanPredicate + return StrictGreaterThanPredicate() + + @memoize_property + def ge(self): + from .relation.equality import GreaterThanPredicate + return GreaterThanPredicate() + + @memoize_property + def lt(self): + from .relation.equality import StrictLessThanPredicate + return StrictLessThanPredicate() + + @memoize_property + def le(self): + from .relation.equality import LessThanPredicate + return LessThanPredicate() + + +Q = AssumptionKeys() + +def _extract_all_facts(assump, exprs): + """ + Extract all relevant assumptions from *assump* with respect to given *exprs*. + + Parameters + ========== + + assump : sympy.assumptions.cnf.CNF + + exprs : tuple of expressions + + Returns + ======= + + sympy.assumptions.cnf.CNF + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.ask import _extract_all_facts + >>> from sympy.abc import x, y + >>> assump = CNF.from_prop(Q.positive(x) & Q.integer(y)) + >>> exprs = (x,) + >>> cnf = _extract_all_facts(assump, exprs) + >>> cnf.clauses + {frozenset({Literal(Q.positive, False)})} + + """ + facts = set() + + for clause in assump.clauses: + args = [] + for literal in clause: + if isinstance(literal.lit, AppliedPredicate) and len(literal.lit.arguments) == 1: + if literal.lit.arg in exprs: + # Add literal if it has matching in it + args.append(Literal(literal.lit.function, literal.is_Not)) + else: + # If any of the literals doesn't have matching expr don't add the whole clause. + break + else: + # If any of the literals aren't unary predicate don't add the whole clause. + break + + else: + if args: + facts.add(frozenset(args)) + return CNF(facts) + + +def ask(proposition, assumptions=True, context=global_assumptions): + """ + Function to evaluate the proposition with assumptions. + + Explanation + =========== + + This function evaluates the proposition to ``True`` or ``False`` if + the truth value can be determined. If not, it returns ``None``. + + It should be discerned from :func:`~.refine()` which, when applied to a + proposition, simplifies the argument to symbolic ``Boolean`` instead of + Python built-in ``True``, ``False`` or ``None``. + + **Syntax** + + * ask(proposition) + Evaluate the *proposition* in global assumption context. + + * ask(proposition, assumptions) + Evaluate the *proposition* with respect to *assumptions* in + global assumption context. + + Parameters + ========== + + proposition : Boolean + Proposition which will be evaluated to boolean value. If this is + not ``AppliedPredicate``, it will be wrapped by ``Q.is_true``. + + assumptions : Boolean, optional + Local assumptions to evaluate the *proposition*. + + context : AssumptionsContext, optional + Default assumptions to evaluate the *proposition*. By default, + this is ``sympy.assumptions.global_assumptions`` variable. + + Returns + ======= + + ``True``, ``False``, or ``None`` + + Raises + ====== + + TypeError : *proposition* or *assumptions* is not valid logical expression. + + ValueError : assumptions are inconsistent. + + 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(4*x), Q.integer(x)) + False + + If the truth value cannot be determined, ``None`` will be returned. + + >>> print(ask(Q.odd(3*x))) # cannot determine unless we know x + None + + ``ValueError`` is raised if assumptions are inconsistent. + + >>> ask(Q.integer(x), Q.even(x) & Q.odd(x)) + Traceback (most recent call last): + ... + ValueError: inconsistent assumptions Q.even(x) & Q.odd(x) + + Notes + ===== + + Relations in assumptions are not implemented (yet), so the following + will not give a meaningful result. + + >>> ask(Q.positive(x), x > 0) + + It is however a work in progress. + + See Also + ======== + + sympy.assumptions.refine.refine : Simplification using assumptions. + Proposition is not reduced to ``None`` if the truth value cannot + be determined. + """ + from sympy.assumptions.satask import satask + from sympy.assumptions.lra_satask import lra_satask + from sympy.logic.algorithms.lra_theory import UnhandledInput + + proposition = sympify(proposition) + assumptions = sympify(assumptions) + + if isinstance(proposition, Predicate) or proposition.kind is not BooleanKind: + raise TypeError("proposition must be a valid logical expression") + + if isinstance(assumptions, Predicate) or assumptions.kind is not BooleanKind: + raise TypeError("assumptions must be a valid logical expression") + + binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} + if isinstance(proposition, AppliedPredicate): + key, args = proposition.function, proposition.arguments + elif proposition.func in binrelpreds: + key, args = binrelpreds[type(proposition)], proposition.args + else: + key, args = Q.is_true, (proposition,) + + # convert local and global assumptions to CNF + assump_cnf = CNF.from_prop(assumptions) + assump_cnf.extend(context) + + # extract the relevant facts from assumptions with respect to args + local_facts = _extract_all_facts(assump_cnf, args) + + # convert default facts and assumed facts to encoded CNF + known_facts_cnf = get_all_known_facts() + enc_cnf = EncodedCNF() + enc_cnf.from_cnf(CNF(known_facts_cnf)) + enc_cnf.add_from_cnf(local_facts) + + # check the satisfiability of given assumptions + if local_facts.clauses and satisfiable(enc_cnf) is False: + raise ValueError("inconsistent assumptions %s" % assumptions) + + # quick computation for single fact + res = _ask_single_fact(key, local_facts) + if res is not None: + return res + + # direct resolution method, no logic + res = key(*args)._eval_ask(assumptions) + if res is not None: + return bool(res) + + # using satask (still costly) + res = satask(proposition, assumptions=assumptions, context=context) + if res is not None: + return res + + try: + res = lra_satask(proposition, assumptions=assumptions, context=context) + except UnhandledInput: + return None + + return res + + +def _ask_single_fact(key, local_facts): + """ + Compute the truth value of single predicate using assumptions. + + Parameters + ========== + + key : sympy.assumptions.assume.Predicate + Proposition predicate. + + local_facts : sympy.assumptions.cnf.CNF + Local assumption in CNF form. + + Returns + ======= + + ``True``, ``False`` or ``None`` + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.ask import _ask_single_fact + + If prerequisite of proposition is rejected by the assumption, + return ``False``. + + >>> key, assump = Q.zero, ~Q.zero + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + >>> key, assump = Q.zero, ~Q.even + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + + If assumption implies the proposition, return ``True``. + + >>> key, assump = Q.even, Q.zero + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + True + + If proposition rejects the assumption, return ``False``. + + >>> key, assump = Q.even, Q.odd + >>> local_facts = CNF.from_prop(assump) + >>> _ask_single_fact(key, local_facts) + False + """ + if local_facts.clauses: + + known_facts_dict = get_known_facts_dict() + + if len(local_facts.clauses) == 1: + cl, = local_facts.clauses + if len(cl) == 1: + f, = cl + prop_facts = known_facts_dict.get(key, None) + prop_req = prop_facts[0] if prop_facts is not None else set() + if f.is_Not and f.arg in prop_req: + # the prerequisite of proposition is rejected + return False + + for clause in local_facts.clauses: + if len(clause) == 1: + f, = clause + prop_facts = known_facts_dict.get(f.arg, None) if not f.is_Not else None + if prop_facts is None: + continue + + prop_req, prop_rej = prop_facts + if key in prop_req: + # assumption implies the proposition + return True + elif key in prop_rej: + # proposition rejects the assumption + return False + + return None + + +def register_handler(key, handler): + """ + Register a handler in the ask system. key must be a string and handler a + class inheriting from AskHandler. + + .. deprecated:: 1.8. + Use multipledispatch handler instead. See :obj:`~.Predicate`. + + """ + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. The register_handler() function + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + if isinstance(key, Predicate): + key = key.name.name + Qkey = getattr(Q, key, None) + if Qkey is not None: + Qkey.add_handler(handler) + else: + setattr(Q, key, Predicate(key, handlers=[handler])) + + +def remove_handler(key, handler): + """ + Removes a handler from the ask system. + + .. deprecated:: 1.8. + Use multipledispatch handler instead. See :obj:`~.Predicate`. + + """ + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. The remove_handler() function + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + if isinstance(key, Predicate): + key = key.name.name + # Don't show the same warning again recursively + with ignore_warnings(SymPyDeprecationWarning): + getattr(Q, key).remove_handler(handler) + + +from sympy.assumptions.ask_generated import (get_all_known_facts, + get_known_facts_dict) diff --git a/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py b/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py new file mode 100644 index 0000000000000000000000000000000000000000..d90cdffc1e127d78e18f70cda13d8d5e0530d41b --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/ask_generated.py @@ -0,0 +1,352 @@ +""" +Do NOT manually edit this file. +Instead, run ./bin/ask_update.py. +""" + +from sympy.assumptions.ask import Q +from sympy.assumptions.cnf import Literal +from sympy.core.cache import cacheit + +@cacheit +def get_all_known_facts(): + """ + Known facts between unary predicates as CNF clauses. + """ + return { + frozenset((Literal(Q.algebraic, False), Literal(Q.imaginary, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.negative, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.positive, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.rational, True))), + frozenset((Literal(Q.algebraic, False), Literal(Q.transcendental, False), Literal(Q.zero, True))), + frozenset((Literal(Q.algebraic, True), Literal(Q.finite, False))), + frozenset((Literal(Q.algebraic, True), Literal(Q.transcendental, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.imaginary, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.finite, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.infinite, True))), + frozenset((Literal(Q.complex_elements, False), Literal(Q.real_elements, True))), + frozenset((Literal(Q.composite, False), Literal(Q.even, True), Literal(Q.positive, True), Literal(Q.prime, False))), + frozenset((Literal(Q.composite, True), Literal(Q.even, False), Literal(Q.odd, False))), + frozenset((Literal(Q.composite, True), Literal(Q.positive, False))), + frozenset((Literal(Q.composite, True), Literal(Q.prime, True))), + frozenset((Literal(Q.diagonal, False), Literal(Q.lower_triangular, True), Literal(Q.upper_triangular, True))), + frozenset((Literal(Q.diagonal, True), Literal(Q.lower_triangular, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.normal, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.symmetric, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.even, False), Literal(Q.odd, False), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.zero, True))), + frozenset((Literal(Q.even, True), Literal(Q.odd, True))), + frozenset((Literal(Q.even, True), Literal(Q.rational, False))), + frozenset((Literal(Q.finite, False), Literal(Q.transcendental, True))), + frozenset((Literal(Q.finite, True), Literal(Q.infinite, True))), + frozenset((Literal(Q.fullrank, False), Literal(Q.invertible, True))), + frozenset((Literal(Q.fullrank, True), Literal(Q.invertible, False), Literal(Q.square, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.negative, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.positive, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.negative, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.positive, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.zero, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.integer_elements, True), Literal(Q.real_elements, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.positive_definite, True))), + frozenset((Literal(Q.invertible, False), Literal(Q.singular, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.singular, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.square, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.negative, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.positive, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.rational, False), Literal(Q.zero, True))), + frozenset((Literal(Q.irrational, True), Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.zero, False))), + frozenset((Literal(Q.irrational, True), Literal(Q.rational, True))), + frozenset((Literal(Q.lower_triangular, False), Literal(Q.triangular, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.lower_triangular, True), Literal(Q.triangular, False))), + frozenset((Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.rational, True), Literal(Q.zero, False))), + frozenset((Literal(Q.negative, True), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.zero, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.normal, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.normal, True), Literal(Q.square, False))), + frozenset((Literal(Q.odd, True), Literal(Q.rational, False))), + frozenset((Literal(Q.orthogonal, False), Literal(Q.real_elements, True), Literal(Q.unitary, True))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.positive_definite, False))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.unitary, False))), + frozenset((Literal(Q.positive, False), Literal(Q.prime, True))), + frozenset((Literal(Q.positive, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.positive, True), Literal(Q.zero, True))), + frozenset((Literal(Q.positive_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.square, False), Literal(Q.symmetric, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.unit_triangular, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.upper_triangular, True))) + } + +@cacheit +def get_all_known_matrix_facts(): + """ + Known facts between unary predicates for matrices as CNF clauses. + """ + return { + frozenset((Literal(Q.complex_elements, False), Literal(Q.real_elements, True))), + frozenset((Literal(Q.diagonal, False), Literal(Q.lower_triangular, True), Literal(Q.upper_triangular, True))), + frozenset((Literal(Q.diagonal, True), Literal(Q.lower_triangular, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.normal, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.symmetric, False))), + frozenset((Literal(Q.diagonal, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.fullrank, False), Literal(Q.invertible, True))), + frozenset((Literal(Q.fullrank, True), Literal(Q.invertible, False), Literal(Q.square, True))), + frozenset((Literal(Q.integer_elements, True), Literal(Q.real_elements, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.positive_definite, True))), + frozenset((Literal(Q.invertible, False), Literal(Q.singular, False))), + frozenset((Literal(Q.invertible, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.singular, True))), + frozenset((Literal(Q.invertible, True), Literal(Q.square, False))), + frozenset((Literal(Q.lower_triangular, False), Literal(Q.triangular, True), Literal(Q.upper_triangular, False))), + frozenset((Literal(Q.lower_triangular, True), Literal(Q.triangular, False))), + frozenset((Literal(Q.normal, False), Literal(Q.unitary, True))), + frozenset((Literal(Q.normal, True), Literal(Q.square, False))), + frozenset((Literal(Q.orthogonal, False), Literal(Q.real_elements, True), Literal(Q.unitary, True))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.positive_definite, False))), + frozenset((Literal(Q.orthogonal, True), Literal(Q.unitary, False))), + frozenset((Literal(Q.square, False), Literal(Q.symmetric, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.unit_triangular, True))), + frozenset((Literal(Q.triangular, False), Literal(Q.upper_triangular, True))) + } + +@cacheit +def get_all_known_number_facts(): + """ + Known facts between unary predicates for numbers as CNF clauses. + """ + return { + frozenset((Literal(Q.algebraic, False), Literal(Q.imaginary, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.negative, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.positive, True), Literal(Q.transcendental, False))), + frozenset((Literal(Q.algebraic, False), Literal(Q.rational, True))), + frozenset((Literal(Q.algebraic, False), Literal(Q.transcendental, False), Literal(Q.zero, True))), + frozenset((Literal(Q.algebraic, True), Literal(Q.finite, False))), + frozenset((Literal(Q.algebraic, True), Literal(Q.transcendental, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.antihermitian, False), Literal(Q.imaginary, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.finite, True))), + frozenset((Literal(Q.commutative, False), Literal(Q.infinite, True))), + frozenset((Literal(Q.composite, False), Literal(Q.even, True), Literal(Q.positive, True), Literal(Q.prime, False))), + frozenset((Literal(Q.composite, True), Literal(Q.even, False), Literal(Q.odd, False))), + frozenset((Literal(Q.composite, True), Literal(Q.positive, False))), + frozenset((Literal(Q.composite, True), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.odd, False), Literal(Q.prime, True))), + frozenset((Literal(Q.even, False), Literal(Q.zero, True))), + frozenset((Literal(Q.even, True), Literal(Q.odd, True))), + frozenset((Literal(Q.even, True), Literal(Q.rational, False))), + frozenset((Literal(Q.finite, False), Literal(Q.transcendental, True))), + frozenset((Literal(Q.finite, True), Literal(Q.infinite, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.negative, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.positive, True))), + frozenset((Literal(Q.hermitian, False), Literal(Q.zero, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.negative, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.positive, True))), + frozenset((Literal(Q.imaginary, True), Literal(Q.zero, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.infinite, False), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.irrational, False), Literal(Q.negative, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.positive, True), Literal(Q.rational, False))), + frozenset((Literal(Q.irrational, False), Literal(Q.rational, False), Literal(Q.zero, True))), + frozenset((Literal(Q.irrational, True), Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.zero, False))), + frozenset((Literal(Q.irrational, True), Literal(Q.rational, True))), + frozenset((Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.rational, True), Literal(Q.zero, False))), + frozenset((Literal(Q.negative, True), Literal(Q.negative_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative, True), Literal(Q.zero, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.negative_infinite, True), Literal(Q.zero, True))), + frozenset((Literal(Q.odd, True), Literal(Q.rational, False))), + frozenset((Literal(Q.positive, False), Literal(Q.prime, True))), + frozenset((Literal(Q.positive, True), Literal(Q.positive_infinite, True))), + frozenset((Literal(Q.positive, True), Literal(Q.zero, True))), + frozenset((Literal(Q.positive_infinite, True), Literal(Q.zero, True))) + } + +@cacheit +def get_known_facts_dict(): + """ + Logical relations between unary predicates as dictionary. + + Each key is a predicate, and item is two groups of predicates. + First group contains the predicates which are implied by the key, and + second group contains the predicates which are rejected by the key. + + """ + return { + Q.algebraic: (set([Q.algebraic, Q.commutative, Q.complex, Q.finite]), + set([Q.infinite, Q.negative_infinite, Q.positive_infinite, + Q.transcendental])), + Q.antihermitian: (set([Q.antihermitian]), set([])), + Q.commutative: (set([Q.commutative]), set([])), + Q.complex: (set([Q.commutative, Q.complex, Q.finite]), + set([Q.infinite, Q.negative_infinite, Q.positive_infinite])), + Q.complex_elements: (set([Q.complex_elements]), set([])), + Q.composite: (set([Q.algebraic, Q.commutative, Q.complex, Q.composite, + Q.extended_nonnegative, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.rational, + Q.real]), set([Q.extended_negative, Q.extended_nonpositive, + Q.imaginary, Q.infinite, Q.irrational, Q.negative, + Q.negative_infinite, Q.nonpositive, Q.positive_infinite, + Q.prime, Q.transcendental, Q.zero])), + Q.diagonal: (set([Q.diagonal, Q.lower_triangular, Q.normal, Q.square, + Q.symmetric, Q.triangular, Q.upper_triangular]), set([])), + Q.even: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, + Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.odd, Q.positive_infinite, + Q.transcendental])), + Q.extended_negative: (set([Q.commutative, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real]), + set([Q.composite, Q.extended_nonnegative, Q.extended_positive, + Q.imaginary, Q.nonnegative, Q.positive, Q.positive_infinite, + Q.prime, Q.zero])), + Q.extended_nonnegative: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_real]), set([Q.extended_negative, Q.imaginary, + Q.negative, Q.negative_infinite])), + Q.extended_nonpositive: (set([Q.commutative, Q.extended_nonpositive, + Q.extended_real]), set([Q.composite, Q.extended_positive, + Q.imaginary, Q.positive, Q.positive_infinite, Q.prime])), + Q.extended_nonzero: (set([Q.commutative, Q.extended_nonzero, + Q.extended_real]), set([Q.imaginary, Q.zero])), + Q.extended_positive: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real]), + set([Q.extended_negative, Q.extended_nonpositive, Q.imaginary, + Q.negative, Q.negative_infinite, Q.nonpositive, Q.zero])), + Q.extended_real: (set([Q.commutative, Q.extended_real]), + set([Q.imaginary])), + Q.finite: (set([Q.commutative, Q.finite]), set([Q.infinite, + Q.negative_infinite, Q.positive_infinite])), + Q.fullrank: (set([Q.fullrank]), set([])), + Q.hermitian: (set([Q.hermitian]), set([])), + Q.imaginary: (set([Q.antihermitian, Q.commutative, Q.complex, + Q.finite, Q.imaginary]), set([Q.composite, Q.even, + Q.extended_negative, Q.extended_nonnegative, + Q.extended_nonpositive, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.infinite, Q.integer, + Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, + Q.positive_infinite, Q.prime, Q.rational, Q.real, Q.zero])), + Q.infinite: (set([Q.commutative, Q.infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.finite, Q.imaginary, + Q.integer, Q.irrational, Q.negative, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.integer: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, + Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental])), + Q.integer_elements: (set([Q.complex_elements, Q.integer_elements, + Q.real_elements]), set([])), + Q.invertible: (set([Q.fullrank, Q.invertible, Q.square]), + set([Q.singular])), + Q.irrational: (set([Q.commutative, Q.complex, Q.extended_nonzero, + Q.extended_real, Q.finite, Q.hermitian, Q.irrational, + Q.nonzero, Q.real]), set([Q.composite, Q.even, Q.imaginary, + Q.infinite, Q.integer, Q.negative_infinite, Q.odd, + Q.positive_infinite, Q.prime, Q.rational, Q.zero])), + Q.is_true: (set([Q.is_true]), set([])), + Q.lower_triangular: (set([Q.lower_triangular, Q.triangular]), set([])), + Q.negative: (set([Q.commutative, Q.complex, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, + Q.finite, Q.hermitian, Q.negative, Q.nonpositive, Q.nonzero, + Q.real]), set([Q.composite, Q.extended_nonnegative, + Q.extended_positive, Q.imaginary, Q.infinite, + Q.negative_infinite, Q.nonnegative, Q.positive, + Q.positive_infinite, Q.prime, Q.zero])), + Q.negative_infinite: (set([Q.commutative, Q.extended_negative, + Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, + Q.infinite, Q.negative_infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.extended_nonnegative, + Q.extended_positive, Q.finite, Q.imaginary, Q.integer, + Q.irrational, Q.negative, Q.nonnegative, Q.nonpositive, + Q.nonzero, Q.odd, Q.positive, Q.positive_infinite, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.noninteger: (set([Q.noninteger]), set([])), + Q.nonnegative: (set([Q.commutative, Q.complex, Q.extended_nonnegative, + Q.extended_real, Q.finite, Q.hermitian, Q.nonnegative, + Q.real]), set([Q.extended_negative, Q.imaginary, Q.infinite, + Q.negative, Q.negative_infinite, Q.positive_infinite])), + Q.nonpositive: (set([Q.commutative, Q.complex, Q.extended_nonpositive, + Q.extended_real, Q.finite, Q.hermitian, Q.nonpositive, + Q.real]), set([Q.composite, Q.extended_positive, Q.imaginary, + Q.infinite, Q.negative_infinite, Q.positive, + Q.positive_infinite, Q.prime])), + Q.nonzero: (set([Q.commutative, Q.complex, Q.extended_nonzero, + Q.extended_real, Q.finite, Q.hermitian, Q.nonzero, Q.real]), + set([Q.imaginary, Q.infinite, Q.negative_infinite, + Q.positive_infinite, Q.zero])), + Q.normal: (set([Q.normal, Q.square]), set([])), + Q.odd: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonzero, Q.odd, Q.rational, Q.real]), + set([Q.even, Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental, + Q.zero])), + Q.orthogonal: (set([Q.fullrank, Q.invertible, Q.normal, Q.orthogonal, + Q.positive_definite, Q.square, Q.unitary]), set([Q.singular])), + Q.positive: (set([Q.commutative, Q.complex, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real, + Q.finite, Q.hermitian, Q.nonnegative, Q.nonzero, Q.positive, + Q.real]), set([Q.extended_negative, Q.extended_nonpositive, + Q.imaginary, Q.infinite, Q.negative, Q.negative_infinite, + Q.nonpositive, Q.positive_infinite, Q.zero])), + Q.positive_definite: (set([Q.fullrank, Q.invertible, + Q.positive_definite, Q.square]), set([Q.singular])), + Q.positive_infinite: (set([Q.commutative, Q.extended_nonnegative, + Q.extended_nonzero, Q.extended_positive, Q.extended_real, + Q.infinite, Q.positive_infinite]), set([Q.algebraic, + Q.complex, Q.composite, Q.even, Q.extended_negative, + Q.extended_nonpositive, Q.finite, Q.imaginary, Q.integer, + Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, + Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, + Q.rational, Q.real, Q.transcendental, Q.zero])), + Q.prime: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_nonnegative, Q.extended_nonzero, + Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, + Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.prime, + Q.rational, Q.real]), set([Q.composite, Q.extended_negative, + Q.extended_nonpositive, Q.imaginary, Q.infinite, Q.irrational, + Q.negative, Q.negative_infinite, Q.nonpositive, + Q.positive_infinite, Q.transcendental, Q.zero])), + Q.rational: (set([Q.algebraic, Q.commutative, Q.complex, + Q.extended_real, Q.finite, Q.hermitian, Q.rational, Q.real]), + set([Q.imaginary, Q.infinite, Q.irrational, + Q.negative_infinite, Q.positive_infinite, Q.transcendental])), + Q.real: (set([Q.commutative, Q.complex, Q.extended_real, Q.finite, + Q.hermitian, Q.real]), set([Q.imaginary, Q.infinite, + Q.negative_infinite, Q.positive_infinite])), + Q.real_elements: (set([Q.complex_elements, Q.real_elements]), set([])), + Q.singular: (set([Q.singular]), set([Q.invertible, Q.orthogonal, + Q.positive_definite, Q.unitary])), + Q.square: (set([Q.square]), set([])), + Q.symmetric: (set([Q.square, Q.symmetric]), set([])), + Q.transcendental: (set([Q.commutative, Q.complex, Q.finite, + Q.transcendental]), set([Q.algebraic, Q.composite, Q.even, + Q.infinite, Q.integer, Q.negative_infinite, Q.odd, + Q.positive_infinite, Q.prime, Q.rational, Q.zero])), + Q.triangular: (set([Q.triangular]), set([])), + Q.unit_triangular: (set([Q.triangular, Q.unit_triangular]), set([])), + Q.unitary: (set([Q.fullrank, Q.invertible, Q.normal, Q.square, + Q.unitary]), set([Q.singular])), + Q.upper_triangular: (set([Q.triangular, Q.upper_triangular]), set([])), + Q.zero: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, + Q.extended_nonnegative, Q.extended_nonpositive, + Q.extended_real, Q.finite, Q.hermitian, Q.integer, + Q.nonnegative, Q.nonpositive, Q.rational, Q.real, Q.zero]), + set([Q.composite, Q.extended_negative, Q.extended_nonzero, + Q.extended_positive, Q.imaginary, Q.infinite, Q.irrational, + Q.negative, Q.negative_infinite, Q.nonzero, Q.odd, Q.positive, + Q.positive_infinite, Q.prime, Q.transcendental])), + } diff --git a/lib/python3.12/site-packages/sympy/assumptions/assume.py b/lib/python3.12/site-packages/sympy/assumptions/assume.py new file mode 100644 index 0000000000000000000000000000000000000000..743195a865a1d39389d471b95728ca79834ed019 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/assume.py @@ -0,0 +1,485 @@ +"""A module which implements predicates and assumption context.""" + +from contextlib import contextmanager +import inspect +from sympy.core.symbol import Str +from sympy.core.sympify import _sympify +from sympy.logic.boolalg import Boolean, false, true +from sympy.multipledispatch.dispatcher import Dispatcher, str_signature +from sympy.utilities.exceptions import sympy_deprecation_warning +from sympy.utilities.iterables import is_sequence +from sympy.utilities.source import get_class + + +class AssumptionsContext(set): + """ + Set containing default assumptions which are applied to the ``ask()`` + function. + + Explanation + =========== + + This is used to represent global assumptions, but you can also use this + class to create your own local assumptions contexts. It is basically a thin + wrapper to Python's set, so see its documentation for advanced usage. + + Examples + ======== + + The default assumption context is ``global_assumptions``, which is initially empty: + + >>> from sympy import ask, Q + >>> from sympy.assumptions import global_assumptions + >>> global_assumptions + AssumptionsContext() + + You can add default assumptions: + + >>> from sympy.abc import x + >>> global_assumptions.add(Q.real(x)) + >>> global_assumptions + AssumptionsContext({Q.real(x)}) + >>> ask(Q.real(x)) + True + + And remove them: + + >>> global_assumptions.remove(Q.real(x)) + >>> print(ask(Q.real(x))) + None + + The ``clear()`` method removes every assumption: + + >>> global_assumptions.add(Q.positive(x)) + >>> global_assumptions + AssumptionsContext({Q.positive(x)}) + >>> global_assumptions.clear() + >>> global_assumptions + AssumptionsContext() + + See Also + ======== + + assuming + + """ + + def add(self, *assumptions): + """Add assumptions.""" + for a in assumptions: + super().add(a) + + def _sympystr(self, printer): + if not self: + return "%s()" % self.__class__.__name__ + return "{}({})".format(self.__class__.__name__, printer._print_set(self)) + +global_assumptions = AssumptionsContext() + + +class AppliedPredicate(Boolean): + """ + The class of expressions resulting from applying ``Predicate`` to + the arguments. ``AppliedPredicate`` merely wraps its argument and + remain unevaluated. To evaluate it, use the ``ask()`` function. + + Examples + ======== + + >>> from sympy import Q, ask + >>> Q.integer(1) + Q.integer(1) + + The ``function`` attribute returns the predicate, and the ``arguments`` + attribute returns the tuple of arguments. + + >>> type(Q.integer(1)) + + >>> Q.integer(1).function + Q.integer + >>> Q.integer(1).arguments + (1,) + + Applied predicates can be evaluated to a boolean value with ``ask``: + + >>> ask(Q.integer(1)) + True + + """ + __slots__ = () + + def __new__(cls, predicate, *args): + if not isinstance(predicate, Predicate): + raise TypeError("%s is not a Predicate." % predicate) + args = map(_sympify, args) + return super().__new__(cls, predicate, *args) + + @property + def arg(self): + """ + Return the expression used by this assumption. + + Examples + ======== + + >>> from sympy import Q, Symbol + >>> x = Symbol('x') + >>> a = Q.integer(x + 1) + >>> a.arg + x + 1 + + """ + # Will be deprecated + args = self._args + if len(args) == 2: + # backwards compatibility + return args[1] + raise TypeError("'arg' property is allowed only for unary predicates.") + + @property + def function(self): + """ + Return the predicate. + """ + # Will be changed to self.args[0] after args overriding is removed + return self._args[0] + + @property + def arguments(self): + """ + Return the arguments which are applied to the predicate. + """ + # Will be changed to self.args[1:] after args overriding is removed + return self._args[1:] + + def _eval_ask(self, assumptions): + return self.function.eval(self.arguments, assumptions) + + @property + def binary_symbols(self): + from .ask import Q + if self.function == Q.is_true: + i = self.arguments[0] + if i.is_Boolean or i.is_Symbol: + return i.binary_symbols + if self.function in (Q.eq, Q.ne): + if true in self.arguments or false in self.arguments: + if self.arguments[0].is_Symbol: + return {self.arguments[0]} + elif self.arguments[1].is_Symbol: + return {self.arguments[1]} + return set() + + +class PredicateMeta(type): + def __new__(cls, clsname, bases, dct): + # If handler is not defined, assign empty dispatcher. + if "handler" not in dct: + name = f"Ask{clsname.capitalize()}Handler" + handler = Dispatcher(name, doc="Handler for key %s" % name) + dct["handler"] = handler + + dct["_orig_doc"] = dct.get("__doc__", "") + + return super().__new__(cls, clsname, bases, dct) + + @property + def __doc__(cls): + handler = cls.handler + doc = cls._orig_doc + if cls is not Predicate and handler is not None: + doc += "Handler\n" + doc += " =======\n\n" + + # Append the handler's doc without breaking sphinx documentation. + docs = [" Multiply dispatched method: %s" % handler.name] + if handler.doc: + for line in handler.doc.splitlines(): + if not line: + continue + docs.append(" %s" % line) + other = [] + for sig in handler.ordering[::-1]: + func = handler.funcs[sig] + if func.__doc__: + s = ' Inputs: <%s>' % str_signature(sig) + lines = [] + for line in func.__doc__.splitlines(): + lines.append(" %s" % line) + s += "\n".join(lines) + docs.append(s) + else: + other.append(str_signature(sig)) + if other: + othersig = " Other signatures:" + for line in other: + othersig += "\n * %s" % line + docs.append(othersig) + + doc += '\n\n'.join(docs) + + return doc + + +class Predicate(Boolean, metaclass=PredicateMeta): + """ + Base class for mathematical predicates. It also serves as a + constructor for undefined predicate objects. + + Explanation + =========== + + Predicate is a function that returns a boolean value [1]. + + Predicate function is object, and it is instance of predicate class. + When a predicate is applied to arguments, ``AppliedPredicate`` + instance is returned. This merely wraps the argument and remain + unevaluated. To obtain the truth value of applied predicate, use the + function ``ask``. + + Evaluation of predicate is done by multiple dispatching. You can + register new handler to the predicate to support new types. + + Every predicate in SymPy can be accessed via the property of ``Q``. + For example, ``Q.even`` returns the predicate which checks if the + argument is even number. + + To define a predicate which can be evaluated, you must subclass this + class, make an instance of it, and register it to ``Q``. After then, + dispatch the handler by argument types. + + If you directly construct predicate using this class, you will get + ``UndefinedPredicate`` which cannot be dispatched. This is useful + when you are building boolean expressions which do not need to be + evaluated. + + Examples + ======== + + Applying and evaluating to boolean value: + + >>> from sympy import Q, ask + >>> ask(Q.prime(7)) + True + + You can define a new predicate by subclassing and dispatching. Here, + we define a predicate for sexy primes [2] as an example. + + >>> from sympy import Predicate, Integer + >>> class SexyPrimePredicate(Predicate): + ... name = "sexyprime" + >>> Q.sexyprime = SexyPrimePredicate() + >>> @Q.sexyprime.register(Integer, Integer) + ... def _(int1, int2, assumptions): + ... args = sorted([int1, int2]) + ... if not all(ask(Q.prime(a), assumptions) for a in args): + ... return False + ... return args[1] - args[0] == 6 + >>> ask(Q.sexyprime(5, 11)) + True + + Direct constructing returns ``UndefinedPredicate``, which can be + applied but cannot be dispatched. + + >>> from sympy import Predicate, Integer + >>> Q.P = Predicate("P") + >>> type(Q.P) + + >>> Q.P(1) + Q.P(1) + >>> Q.P.register(Integer)(lambda expr, assump: True) + Traceback (most recent call last): + ... + TypeError: cannot be dispatched. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Predicate_%28mathematical_logic%29 + .. [2] https://en.wikipedia.org/wiki/Sexy_prime + + """ + + is_Atom = True + + def __new__(cls, *args, **kwargs): + if cls is Predicate: + return UndefinedPredicate(*args, **kwargs) + obj = super().__new__(cls, *args) + return obj + + @property + def name(self): + # May be overridden + return type(self).__name__ + + @classmethod + def register(cls, *types, **kwargs): + """ + Register the signature to the handler. + """ + if cls.handler is None: + raise TypeError("%s cannot be dispatched." % type(cls)) + return cls.handler.register(*types, **kwargs) + + @classmethod + def register_many(cls, *types, **kwargs): + """ + Register multiple signatures to same handler. + """ + def _(func): + for t in types: + if not is_sequence(t): + t = (t,) # for convenience, allow passing `type` to mean `(type,)` + cls.register(*t, **kwargs)(func) + return _ + + def __call__(self, *args): + return AppliedPredicate(self, *args) + + def eval(self, args, assumptions=True): + """ + Evaluate ``self(*args)`` under the given assumptions. + + This uses only direct resolution methods, not logical inference. + """ + result = None + try: + result = self.handler(*args, assumptions=assumptions) + except NotImplementedError: + pass + return result + + def _eval_refine(self, assumptions): + # When Predicate is no longer Boolean, delete this method + return self + + +class UndefinedPredicate(Predicate): + """ + Predicate without handler. + + Explanation + =========== + + This predicate is generated by using ``Predicate`` directly for + construction. It does not have a handler, and evaluating this with + arguments is done by SAT solver. + + Examples + ======== + + >>> from sympy import Predicate, Q + >>> Q.P = Predicate('P') + >>> Q.P.func + + >>> Q.P.name + Str('P') + + """ + + handler = None + + def __new__(cls, name, handlers=None): + # "handlers" parameter supports old design + if not isinstance(name, Str): + name = Str(name) + obj = super(Boolean, cls).__new__(cls, name) + obj.handlers = handlers or [] + return obj + + @property + def name(self): + return self.args[0] + + def _hashable_content(self): + return (self.name,) + + def __getnewargs__(self): + return (self.name,) + + def __call__(self, expr): + return AppliedPredicate(self, expr) + + def add_handler(self, handler): + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Predicate.add_handler() + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + self.handlers.append(handler) + + def remove_handler(self, handler): + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Predicate.remove_handler() + should be replaced with the multipledispatch handler of Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + ) + self.handlers.remove(handler) + + def eval(self, args, assumptions=True): + # Support for deprecated design + # When old design is removed, this will always return None + sympy_deprecation_warning( + """ + The AskHandler system is deprecated. Evaluating UndefinedPredicate + objects should be replaced with the multipledispatch handler of + Predicate. + """, + deprecated_since_version="1.8", + active_deprecations_target='deprecated-askhandler', + stacklevel=5, + ) + expr, = args + res, _res = None, None + mro = inspect.getmro(type(expr)) + for handler in self.handlers: + cls = get_class(handler) + for subclass in mro: + eval_ = getattr(cls, subclass.__name__, None) + if eval_ is None: + continue + res = eval_(expr, assumptions) + # Do not stop if value returned is None + # Try to check for higher classes + if res is None: + continue + if _res is None: + _res = res + else: + # only check consistency if both resolutors have concluded + if _res != res: + raise ValueError('incompatible resolutors') + break + return res + + +@contextmanager +def assuming(*assumptions): + """ + Context manager for assumptions. + + Examples + ======== + + >>> from sympy import assuming, Q, ask + >>> from sympy.abc import x, y + >>> print(ask(Q.integer(x + y))) + None + >>> with assuming(Q.integer(x), Q.integer(y)): + ... print(ask(Q.integer(x + y))) + True + """ + old_global_assumptions = global_assumptions.copy() + global_assumptions.update(assumptions) + try: + yield + finally: + global_assumptions.clear() + global_assumptions.update(old_global_assumptions) diff --git a/lib/python3.12/site-packages/sympy/assumptions/cnf.py b/lib/python3.12/site-packages/sympy/assumptions/cnf.py new file mode 100644 index 0000000000000000000000000000000000000000..a95d27bed6eeb64c42f4edd9d49bd8e5753069e5 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/cnf.py @@ -0,0 +1,445 @@ +""" +The classes used here are for the internal use of assumptions system +only and should not be used anywhere else as these do not possess the +signatures common to SymPy objects. For general use of logic constructs +please refer to sympy.logic classes And, Or, Not, etc. +""" +from itertools import combinations, product, zip_longest +from sympy.assumptions.assume import AppliedPredicate, Predicate +from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le +from sympy.core.singleton import S +from sympy.logic.boolalg import Or, And, Not, Xnor +from sympy.logic.boolalg import (Equivalent, ITE, Implies, Nand, Nor, Xor) + + +class Literal: + """ + The smallest element of a CNF object. + + Parameters + ========== + + lit : Boolean expression + + is_Not : bool + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import Literal + >>> from sympy.abc import x + >>> Literal(Q.even(x)) + Literal(Q.even(x), False) + >>> Literal(~Q.even(x)) + Literal(Q.even(x), True) + """ + + def __new__(cls, lit, is_Not=False): + if isinstance(lit, Not): + lit = lit.args[0] + is_Not = True + elif isinstance(lit, (AND, OR, Literal)): + return ~lit if is_Not else lit + obj = super().__new__(cls) + obj.lit = lit + obj.is_Not = is_Not + return obj + + @property + def arg(self): + return self.lit + + def rcall(self, expr): + if callable(self.lit): + lit = self.lit(expr) + else: + lit = self.lit.apply(expr) + return type(self)(lit, self.is_Not) + + def __invert__(self): + is_Not = not self.is_Not + return Literal(self.lit, is_Not) + + def __str__(self): + return '{}({}, {})'.format(type(self).__name__, self.lit, self.is_Not) + + __repr__ = __str__ + + def __eq__(self, other): + return self.arg == other.arg and self.is_Not == other.is_Not + + def __hash__(self): + h = hash((type(self).__name__, self.arg, self.is_Not)) + return h + + +class OR: + """ + A low-level implementation for Or + """ + def __init__(self, *args): + self._args = args + + @property + def args(self): + return sorted(self._args, key=str) + + def rcall(self, expr): + return type(self)(*[arg.rcall(expr) + for arg in self._args + ]) + + def __invert__(self): + return AND(*[~arg for arg in self._args]) + + def __hash__(self): + return hash((type(self).__name__,) + tuple(self.args)) + + def __eq__(self, other): + return self.args == other.args + + def __str__(self): + s = '(' + ' | '.join([str(arg) for arg in self.args]) + ')' + return s + + __repr__ = __str__ + + +class AND: + """ + A low-level implementation for And + """ + def __init__(self, *args): + self._args = args + + def __invert__(self): + return OR(*[~arg for arg in self._args]) + + @property + def args(self): + return sorted(self._args, key=str) + + def rcall(self, expr): + return type(self)(*[arg.rcall(expr) + for arg in self._args + ]) + + def __hash__(self): + return hash((type(self).__name__,) + tuple(self.args)) + + def __eq__(self, other): + return self.args == other.args + + def __str__(self): + s = '('+' & '.join([str(arg) for arg in self.args])+')' + return s + + __repr__ = __str__ + + +def to_NNF(expr, composite_map=None): + """ + Generates the Negation Normal Form of any boolean expression in terms + of AND, OR, and Literal objects. + + Examples + ======== + + >>> from sympy import Q, Eq + >>> from sympy.assumptions.cnf import to_NNF + >>> from sympy.abc import x, y + >>> expr = Q.even(x) & ~Q.positive(x) + >>> to_NNF(expr) + (Literal(Q.even(x), False) & Literal(Q.positive(x), True)) + + Supported boolean objects are converted to corresponding predicates. + + >>> to_NNF(Eq(x, y)) + Literal(Q.eq(x, y), False) + + If ``composite_map`` argument is given, ``to_NNF`` decomposes the + specified predicate into a combination of primitive predicates. + + >>> cmap = {Q.nonpositive: Q.negative | Q.zero} + >>> to_NNF(Q.nonpositive, cmap) + (Literal(Q.negative, False) | Literal(Q.zero, False)) + >>> to_NNF(Q.nonpositive(x), cmap) + (Literal(Q.negative(x), False) | Literal(Q.zero(x), False)) + """ + from sympy.assumptions.ask import Q + + if composite_map is None: + composite_map = {} + + + binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} + if type(expr) in binrelpreds: + pred = binrelpreds[type(expr)] + expr = pred(*expr.args) + + if isinstance(expr, Not): + arg = expr.args[0] + tmp = to_NNF(arg, composite_map) # Strategy: negate the NNF of expr + return ~tmp + + if isinstance(expr, Or): + return OR(*[to_NNF(x, composite_map) for x in Or.make_args(expr)]) + + if isinstance(expr, And): + return AND(*[to_NNF(x, composite_map) for x in And.make_args(expr)]) + + if isinstance(expr, Nand): + tmp = AND(*[to_NNF(x, composite_map) for x in expr.args]) + return ~tmp + + if isinstance(expr, Nor): + tmp = OR(*[to_NNF(x, composite_map) for x in expr.args]) + return ~tmp + + if isinstance(expr, Xor): + cnfs = [] + for i in range(0, len(expr.args) + 1, 2): + for neg in combinations(expr.args, i): + clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) + for s in expr.args] + cnfs.append(OR(*clause)) + return AND(*cnfs) + + if isinstance(expr, Xnor): + cnfs = [] + for i in range(0, len(expr.args) + 1, 2): + for neg in combinations(expr.args, i): + clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) + for s in expr.args] + cnfs.append(OR(*clause)) + return ~AND(*cnfs) + + if isinstance(expr, Implies): + L, R = to_NNF(expr.args[0], composite_map), to_NNF(expr.args[1], composite_map) + return OR(~L, R) + + if isinstance(expr, Equivalent): + cnfs = [] + for a, b in zip_longest(expr.args, expr.args[1:], fillvalue=expr.args[0]): + a = to_NNF(a, composite_map) + b = to_NNF(b, composite_map) + cnfs.append(OR(~a, b)) + return AND(*cnfs) + + if isinstance(expr, ITE): + L = to_NNF(expr.args[0], composite_map) + M = to_NNF(expr.args[1], composite_map) + R = to_NNF(expr.args[2], composite_map) + return AND(OR(~L, M), OR(L, R)) + + if isinstance(expr, AppliedPredicate): + pred, args = expr.function, expr.arguments + newpred = composite_map.get(pred, None) + if newpred is not None: + return to_NNF(newpred.rcall(*args), composite_map) + + if isinstance(expr, Predicate): + newpred = composite_map.get(expr, None) + if newpred is not None: + return to_NNF(newpred, composite_map) + + return Literal(expr) + + +def distribute_AND_over_OR(expr): + """ + Distributes AND over OR in the NNF expression. + Returns the result( Conjunctive Normal Form of expression) + as a CNF object. + """ + if not isinstance(expr, (AND, OR)): + tmp = set() + tmp.add(frozenset((expr,))) + return CNF(tmp) + + if isinstance(expr, OR): + return CNF.all_or(*[distribute_AND_over_OR(arg) + for arg in expr._args]) + + if isinstance(expr, AND): + return CNF.all_and(*[distribute_AND_over_OR(arg) + for arg in expr._args]) + + +class CNF: + """ + Class to represent CNF of a Boolean expression. + Consists of set of clauses, which themselves are stored as + frozenset of Literal objects. + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.abc import x + >>> cnf = CNF.from_prop(Q.real(x) & ~Q.zero(x)) + >>> cnf.clauses + {frozenset({Literal(Q.zero(x), True)}), + frozenset({Literal(Q.negative(x), False), + Literal(Q.positive(x), False), Literal(Q.zero(x), False)})} + """ + def __init__(self, clauses=None): + if not clauses: + clauses = set() + self.clauses = clauses + + def add(self, prop): + clauses = CNF.to_CNF(prop).clauses + self.add_clauses(clauses) + + def __str__(self): + s = ' & '.join( + ['(' + ' | '.join([str(lit) for lit in clause]) +')' + for clause in self.clauses] + ) + return s + + def extend(self, props): + for p in props: + self.add(p) + return self + + def copy(self): + return CNF(set(self.clauses)) + + def add_clauses(self, clauses): + self.clauses |= clauses + + @classmethod + def from_prop(cls, prop): + res = cls() + res.add(prop) + return res + + def __iand__(self, other): + self.add_clauses(other.clauses) + return self + + def all_predicates(self): + predicates = set() + for c in self.clauses: + predicates |= {arg.lit for arg in c} + return predicates + + def _or(self, cnf): + clauses = set() + for a, b in product(self.clauses, cnf.clauses): + tmp = set(a) + tmp.update(b) + clauses.add(frozenset(tmp)) + return CNF(clauses) + + def _and(self, cnf): + clauses = self.clauses.union(cnf.clauses) + return CNF(clauses) + + def _not(self): + clss = list(self.clauses) + ll = {frozenset((~x,)) for x in clss[-1]} + ll = CNF(ll) + + for rest in clss[:-1]: + p = {frozenset((~x,)) for x in rest} + ll = ll._or(CNF(p)) + return ll + + def rcall(self, expr): + clause_list = [] + for clause in self.clauses: + lits = [arg.rcall(expr) for arg in clause] + clause_list.append(OR(*lits)) + expr = AND(*clause_list) + return distribute_AND_over_OR(expr) + + @classmethod + def all_or(cls, *cnfs): + b = cnfs[0].copy() + for rest in cnfs[1:]: + b = b._or(rest) + return b + + @classmethod + def all_and(cls, *cnfs): + b = cnfs[0].copy() + for rest in cnfs[1:]: + b = b._and(rest) + return b + + @classmethod + def to_CNF(cls, expr): + from sympy.assumptions.facts import get_composite_predicates + expr = to_NNF(expr, get_composite_predicates()) + expr = distribute_AND_over_OR(expr) + return expr + + @classmethod + def CNF_to_cnf(cls, cnf): + """ + Converts CNF object to SymPy's boolean expression + retaining the form of expression. + """ + def remove_literal(arg): + return Not(arg.lit) if arg.is_Not else arg.lit + + return And(*(Or(*(remove_literal(arg) for arg in clause)) for clause in cnf.clauses)) + + +class EncodedCNF: + """ + Class for encoding the CNF expression. + """ + def __init__(self, data=None, encoding=None): + if not data and not encoding: + data = [] + encoding = {} + self.data = data + self.encoding = encoding + self._symbols = list(encoding.keys()) + + def from_cnf(self, cnf): + self._symbols = list(cnf.all_predicates()) + n = len(self._symbols) + self.encoding = dict(zip(self._symbols, range(1, n + 1))) + self.data = [self.encode(clause) for clause in cnf.clauses] + + @property + def symbols(self): + return self._symbols + + @property + def variables(self): + return range(1, len(self._symbols) + 1) + + def copy(self): + new_data = [set(clause) for clause in self.data] + return EncodedCNF(new_data, dict(self.encoding)) + + def add_prop(self, prop): + cnf = CNF.from_prop(prop) + self.add_from_cnf(cnf) + + def add_from_cnf(self, cnf): + clauses = [self.encode(clause) for clause in cnf.clauses] + self.data += clauses + + def encode_arg(self, arg): + literal = arg.lit + value = self.encoding.get(literal, None) + if value is None: + n = len(self._symbols) + self._symbols.append(literal) + value = self.encoding[literal] = n + 1 + if arg.is_Not: + return -value + else: + return value + + def encode(self, clause): + return {self.encode_arg(arg) if not arg.lit == S.false else 0 for arg in clause} diff --git a/lib/python3.12/site-packages/sympy/assumptions/facts.py b/lib/python3.12/site-packages/sympy/assumptions/facts.py new file mode 100644 index 0000000000000000000000000000000000000000..2ff268677cf74e252ac6c3bc3eecbea08b9414d0 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/facts.py @@ -0,0 +1,270 @@ +""" +Known facts in assumptions module. + +This module defines the facts between unary predicates in ``get_known_facts()``, +and supports functions to generate the contents in +``sympy.assumptions.ask_generated`` file. +""" + +from sympy.assumptions.ask import Q +from sympy.assumptions.assume import AppliedPredicate +from sympy.core.cache import cacheit +from sympy.core.symbol import Symbol +from sympy.logic.boolalg import (to_cnf, And, Not, Implies, Equivalent, + Exclusive,) +from sympy.logic.inference import satisfiable + + +@cacheit +def get_composite_predicates(): + # To reduce the complexity of sat solver, these predicates are + # transformed into the combination of primitive predicates. + return { + Q.real : Q.negative | Q.zero | Q.positive, + Q.integer : Q.even | Q.odd, + Q.nonpositive : Q.negative | Q.zero, + Q.nonzero : Q.negative | Q.positive, + Q.nonnegative : Q.zero | Q.positive, + Q.extended_real : Q.negative_infinite | Q.negative | Q.zero | Q.positive | Q.positive_infinite, + Q.extended_positive: Q.positive | Q.positive_infinite, + Q.extended_negative: Q.negative | Q.negative_infinite, + Q.extended_nonzero: Q.negative_infinite | Q.negative | Q.positive | Q.positive_infinite, + Q.extended_nonpositive: Q.negative_infinite | Q.negative | Q.zero, + Q.extended_nonnegative: Q.zero | Q.positive | Q.positive_infinite, + Q.complex : Q.algebraic | Q.transcendental + } + + +@cacheit +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( + get_number_facts(x), + get_matrix_facts(x) + ) + return fact + + +@cacheit +def get_number_facts(x = None): + """ + Facts between unary number 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)), + ) + return fact + + +@cacheit +def get_matrix_facts(x = None): + """ + Facts between unary matrix 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( + # 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 + + + +def generate_known_facts_dict(keys, fact): + """ + Computes and returns a dictionary which contains the relations between + unary predicates. + + Each key is a predicate, and item is two groups of predicates. + First group contains the predicates which are implied by the key, and + second group contains the predicates which are rejected by the key. + + All predicates in *keys* and *fact* must be unary and have same placeholder + symbol. + + Parameters + ========== + + keys : list of AppliedPredicate instances. + + fact : Fact between predicates in conjugated normal form. + + Examples + ======== + + >>> from sympy import Q, And, Implies + >>> from sympy.assumptions.facts import generate_known_facts_dict + >>> from sympy.abc import x + >>> keys = [Q.even(x), Q.odd(x), Q.zero(x)] + >>> fact = And(Implies(Q.even(x), ~Q.odd(x)), + ... Implies(Q.zero(x), Q.even(x))) + >>> generate_known_facts_dict(keys, fact) + {Q.even: ({Q.even}, {Q.odd}), + Q.odd: ({Q.odd}, {Q.even, Q.zero}), + Q.zero: ({Q.even, Q.zero}, {Q.odd})} + """ + fact_cnf = to_cnf(fact) + mapping = single_fact_lookup(keys, fact_cnf) + + ret = {} + for key, value in mapping.items(): + implied = set() + rejected = set() + for expr in value: + if isinstance(expr, AppliedPredicate): + implied.add(expr.function) + elif isinstance(expr, Not): + pred = expr.args[0] + rejected.add(pred.function) + ret[key.function] = (implied, rejected) + return ret + + +@cacheit +def get_known_facts_keys(): + """ + Return every unary predicates registered to ``Q``. + + This function is used to generate the keys for + ``generate_known_facts_dict``. + + """ + # exclude polyadic predicates + exclude = {Q.eq, Q.ne, Q.gt, Q.lt, Q.ge, Q.le} + + result = [] + for attr in Q.__class__.__dict__: + if attr.startswith('__'): + continue + pred = getattr(Q, attr) + if pred in exclude: + continue + result.append(pred) + return result + + +def single_fact_lookup(known_facts_keys, known_facts_cnf): + # Return the dictionary for quick lookup of single fact + mapping = {} + for key in known_facts_keys: + mapping[key] = {key} + for other_key in known_facts_keys: + if other_key != key: + if ask_full_inference(other_key, key, known_facts_cnf): + mapping[key].add(other_key) + if ask_full_inference(~other_key, key, known_facts_cnf): + mapping[key].add(~other_key) + return mapping + + +def ask_full_inference(proposition, assumptions, known_facts_cnf): + """ + Method for inferring properties about objects. + + """ + if not satisfiable(And(known_facts_cnf, assumptions, proposition)): + return False + if not satisfiable(And(known_facts_cnf, assumptions, Not(proposition))): + return True + return None diff --git a/lib/python3.12/site-packages/sympy/assumptions/handlers/calculus.py b/lib/python3.12/site-packages/sympy/assumptions/handlers/calculus.py new file mode 100644 index 0000000000000000000000000000000000000000..263bed6da00cc57e198032d06f835ead374573d2 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/handlers/calculus.py @@ -0,0 +1,258 @@ +""" +This module contains query handlers responsible for calculus queries: +infinitesimal, finite, etc. +""" + +from sympy.assumptions import Q, ask +from sympy.core import Add, Mul, Pow, Symbol +from sympy.core.numbers import (NegativeInfinity, GoldenRatio, + Infinity, Exp1, ComplexInfinity, ImaginaryUnit, NaN, Number, Pi, E, + TribonacciConstant) +from sympy.functions import cos, exp, log, sign, sin +from sympy.logic.boolalg import conjuncts + +from ..predicates.calculus import (FinitePredicate, InfinitePredicate, + PositiveInfinitePredicate, NegativeInfinitePredicate) + + +# FinitePredicate + + +@FinitePredicate.register(Symbol) +def _(expr, assumptions): + """ + Handles Symbol. + """ + if expr.is_finite is not None: + return expr.is_finite + if Q.finite(expr) in conjuncts(assumptions): + return True + return None + +@FinitePredicate.register(Add) +def _(expr, assumptions): + """ + Return True if expr is bounded, False if not and None if unknown. + + Truth Table: + + +-------+-----+-----------+-----------+ + | | | | | + | | B | U | ? | + | | | | | + +-------+-----+---+---+---+---+---+---+ + | | | | | | | | | + | | |'+'|'-'|'x'|'+'|'-'|'x'| + | | | | | | | | | + +-------+-----+---+---+---+---+---+---+ + | | | | | + | B | B | U | ? | + | | | | | + +---+---+-----+---+---+---+---+---+---+ + | | | | | | | | | | + | |'+'| | U | ? | ? | U | ? | ? | + | | | | | | | | | | + | +---+-----+---+---+---+---+---+---+ + | | | | | | | | | | + | U |'-'| | ? | U | ? | ? | U | ? | + | | | | | | | | | | + | +---+-----+---+---+---+---+---+---+ + | | | | | | + | |'x'| | ? | ? | + | | | | | | + +---+---+-----+---+---+---+---+---+---+ + | | | | | + | ? | | | ? | + | | | | | + +-------+-----+-----------+---+---+---+ + + * 'B' = Bounded + + * 'U' = Unbounded + + * '?' = unknown boundedness + + * '+' = positive sign + + * '-' = negative sign + + * 'x' = sign unknown + + * All Bounded -> True + + * 1 Unbounded and the rest Bounded -> False + + * >1 Unbounded, all with same known sign -> False + + * Any Unknown and unknown sign -> None + + * Else -> None + + When the signs are not the same you can have an undefined + result as in oo - oo, hence 'bounded' is also undefined. + """ + sign = -1 # sign of unknown or infinite + result = True + for arg in expr.args: + _bounded = ask(Q.finite(arg), assumptions) + if _bounded: + continue + s = ask(Q.extended_positive(arg), assumptions) + # if there has been more than one sign or if the sign of this arg + # is None and Bounded is None or there was already + # an unknown sign, return None + if sign != -1 and s != sign or \ + s is None and None in (_bounded, sign): + return None + else: + sign = s + # once False, do not change + if result is not False: + result = _bounded + return result + +@FinitePredicate.register(Mul) +def _(expr, assumptions): + """ + Return True if expr is bounded, False if not and None if unknown. + + Truth Table: + + +---+---+---+--------+ + | | | | | + | | B | U | ? | + | | | | | + +---+---+---+---+----+ + | | | | | | + | | | | s | /s | + | | | | | | + +---+---+---+---+----+ + | | | | | + | B | B | U | ? | + | | | | | + +---+---+---+---+----+ + | | | | | | + | U | | U | U | ? | + | | | | | | + +---+---+---+---+----+ + | | | | | + | ? | | | ? | + | | | | | + +---+---+---+---+----+ + + * B = Bounded + + * U = Unbounded + + * ? = unknown boundedness + + * s = signed (hence nonzero) + + * /s = not signed + """ + result = True + for arg in expr.args: + _bounded = ask(Q.finite(arg), assumptions) + if _bounded: + continue + elif _bounded is None: + if result is None: + return None + if ask(Q.extended_nonzero(arg), assumptions) is None: + return None + if result is not False: + result = None + else: + result = False + return result + +@FinitePredicate.register(Pow) +def _(expr, assumptions): + """ + * Unbounded ** NonZero -> Unbounded + + * Bounded ** Bounded -> Bounded + + * Abs()<=1 ** Positive -> Bounded + + * Abs()>=1 ** Negative -> Bounded + + * Otherwise unknown + """ + if expr.base == E: + return ask(Q.finite(expr.exp), assumptions) + + base_bounded = ask(Q.finite(expr.base), assumptions) + exp_bounded = ask(Q.finite(expr.exp), assumptions) + if base_bounded is None and exp_bounded is None: # Common Case + return None + if base_bounded is False and ask(Q.extended_nonzero(expr.exp), assumptions): + return False + if base_bounded and exp_bounded: + return True + if (abs(expr.base) <= 1) == True and ask(Q.extended_positive(expr.exp), assumptions): + return True + if (abs(expr.base) >= 1) == True and ask(Q.extended_negative(expr.exp), assumptions): + return True + if (abs(expr.base) >= 1) == True and exp_bounded is False: + return False + return None + +@FinitePredicate.register(exp) +def _(expr, assumptions): + return ask(Q.finite(expr.exp), assumptions) + +@FinitePredicate.register(log) +def _(expr, assumptions): + # After complex -> finite fact is registered to new assumption system, + # querying Q.infinite may be removed. + if ask(Q.infinite(expr.args[0]), assumptions): + return False + return ask(~Q.zero(expr.args[0]), assumptions) + +@FinitePredicate.register_many(cos, sin, Number, Pi, Exp1, GoldenRatio, + TribonacciConstant, ImaginaryUnit, sign) +def _(expr, assumptions): + return True + +@FinitePredicate.register_many(ComplexInfinity, Infinity, NegativeInfinity) +def _(expr, assumptions): + return False + +@FinitePredicate.register(NaN) +def _(expr, assumptions): + return None + + +# InfinitePredicate + + +@InfinitePredicate.register_many(ComplexInfinity, Infinity, NegativeInfinity) +def _(expr, assumptions): + return True + + +# PositiveInfinitePredicate + + +@PositiveInfinitePredicate.register(Infinity) +def _(expr, assumptions): + return True + + +@PositiveInfinitePredicate.register_many(NegativeInfinity, ComplexInfinity) +def _(expr, assumptions): + return False + + +# NegativeInfinitePredicate + + +@NegativeInfinitePredicate.register(NegativeInfinity) +def _(expr, assumptions): + return True + + +@NegativeInfinitePredicate.register_many(Infinity, ComplexInfinity) +def _(expr, assumptions): + return False diff --git a/lib/python3.12/site-packages/sympy/assumptions/handlers/matrices.py b/lib/python3.12/site-packages/sympy/assumptions/handlers/matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..3b20385360136629ea037eb7238c45b70ba57fd2 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/handlers/matrices.py @@ -0,0 +1,716 @@ +""" +This module contains query handlers responsible for Matrices queries: +Square, Symmetric, Invertible etc. +""" + +from sympy.logic.boolalg import conjuncts +from sympy.assumptions import Q, ask +from sympy.assumptions.handlers import test_closed_group +from sympy.matrices import MatrixBase +from sympy.matrices.expressions import (BlockMatrix, BlockDiagMatrix, Determinant, + DiagMatrix, DiagonalMatrix, HadamardProduct, Identity, Inverse, MatAdd, MatMul, + MatPow, MatrixExpr, MatrixSlice, MatrixSymbol, OneMatrix, Trace, Transpose, + ZeroMatrix) +from sympy.matrices.expressions.blockmatrix import reblock_2x2 +from sympy.matrices.expressions.factorizations import Factorization +from sympy.matrices.expressions.fourier import DFT +from sympy.core.logic import fuzzy_and +from sympy.utilities.iterables import sift +from sympy.core import Basic + +from ..predicates.matrices import (SquarePredicate, SymmetricPredicate, + InvertiblePredicate, OrthogonalPredicate, UnitaryPredicate, + FullRankPredicate, PositiveDefinitePredicate, UpperTriangularPredicate, + LowerTriangularPredicate, DiagonalPredicate, IntegerElementsPredicate, + RealElementsPredicate, ComplexElementsPredicate) + + +def _Factorization(predicate, expr, assumptions): + if predicate in expr.predicates: + return True + + +# SquarePredicate + +@SquarePredicate.register(MatrixExpr) +def _(expr, assumptions): + return expr.shape[0] == expr.shape[1] + + +# SymmetricPredicate + +@SymmetricPredicate.register(MatMul) +def _(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if all(ask(Q.symmetric(arg), assumptions) for arg in mmul.args): + return True + # TODO: implement sathandlers system for the matrices. + # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). + if ask(Q.diagonal(expr), assumptions): + return True + if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T: + if len(mmul.args) == 2: + return True + return ask(Q.symmetric(MatMul(*mmul.args[1:-1])), assumptions) + +@SymmetricPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.symmetric(base), assumptions) + return None + +@SymmetricPredicate.register(MatAdd) +def _(expr, assumptions): + return all(ask(Q.symmetric(arg), assumptions) for arg in expr.args) + +@SymmetricPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if not expr.is_square: + return False + # TODO: implement sathandlers system for the matrices. + # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). + if ask(Q.diagonal(expr), assumptions): + return True + if Q.symmetric(expr) in conjuncts(assumptions): + return True + +@SymmetricPredicate.register_many(OneMatrix, ZeroMatrix) +def _(expr, assumptions): + return ask(Q.square(expr), assumptions) + +@SymmetricPredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.symmetric(expr.arg), assumptions) + +@SymmetricPredicate.register(MatrixSlice) +def _(expr, assumptions): + # TODO: implement sathandlers system for the matrices. + # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). + if ask(Q.diagonal(expr), assumptions): + return True + if not expr.on_diag: + return None + else: + return ask(Q.symmetric(expr.parent), assumptions) + +@SymmetricPredicate.register(Identity) +def _(expr, assumptions): + return True + + +# InvertiblePredicate + +@InvertiblePredicate.register(MatMul) +def _(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if all(ask(Q.invertible(arg), assumptions) for arg in mmul.args): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + +@InvertiblePredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + if exp.is_negative == False: + return ask(Q.invertible(base), assumptions) + return None + +@InvertiblePredicate.register(MatAdd) +def _(expr, assumptions): + return None + +@InvertiblePredicate.register(MatrixSymbol) +def _(expr, assumptions): + if not expr.is_square: + return False + if Q.invertible(expr) in conjuncts(assumptions): + return True + +@InvertiblePredicate.register_many(Identity, Inverse) +def _(expr, assumptions): + return True + +@InvertiblePredicate.register(ZeroMatrix) +def _(expr, assumptions): + return False + +@InvertiblePredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@InvertiblePredicate.register(Transpose) +def _(expr, assumptions): + return ask(Q.invertible(expr.arg), assumptions) + +@InvertiblePredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.invertible(expr.parent), assumptions) + +@InvertiblePredicate.register(MatrixBase) +def _(expr, assumptions): + if not expr.is_square: + return False + return expr.rank() == expr.rows + +@InvertiblePredicate.register(MatrixExpr) +def _(expr, assumptions): + if not expr.is_square: + return False + return None + +@InvertiblePredicate.register(BlockMatrix) +def _(expr, assumptions): + if not expr.is_square: + return False + if expr.blockshape == (1, 1): + return ask(Q.invertible(expr.blocks[0, 0]), assumptions) + expr = reblock_2x2(expr) + if expr.blockshape == (2, 2): + [[A, B], [C, D]] = expr.blocks.tolist() + if ask(Q.invertible(A), assumptions) == True: + invertible = ask(Q.invertible(D - C * A.I * B), assumptions) + if invertible is not None: + return invertible + if ask(Q.invertible(B), assumptions) == True: + invertible = ask(Q.invertible(C - D * B.I * A), assumptions) + if invertible is not None: + return invertible + if ask(Q.invertible(C), assumptions) == True: + invertible = ask(Q.invertible(B - A * C.I * D), assumptions) + if invertible is not None: + return invertible + if ask(Q.invertible(D), assumptions) == True: + invertible = ask(Q.invertible(A - B * D.I * C), assumptions) + if invertible is not None: + return invertible + return None + +@InvertiblePredicate.register(BlockDiagMatrix) +def _(expr, assumptions): + if expr.rowblocksizes != expr.colblocksizes: + return None + return fuzzy_and([ask(Q.invertible(a), assumptions) for a in expr.diag]) + + +# OrthogonalPredicate + +@OrthogonalPredicate.register(MatMul) +def _(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.orthogonal(arg), assumptions) for arg in mmul.args) and + factor == 1): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + +@OrthogonalPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if int_exp: + return ask(Q.orthogonal(base), assumptions) + return None + +@OrthogonalPredicate.register(MatAdd) +def _(expr, assumptions): + if (len(expr.args) == 1 and + ask(Q.orthogonal(expr.args[0]), assumptions)): + return True + +@OrthogonalPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if (not expr.is_square or + ask(Q.invertible(expr), assumptions) is False): + return False + if Q.orthogonal(expr) in conjuncts(assumptions): + return True + +@OrthogonalPredicate.register(Identity) +def _(expr, assumptions): + return True + +@OrthogonalPredicate.register(ZeroMatrix) +def _(expr, assumptions): + return False + +@OrthogonalPredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.orthogonal(expr.arg), assumptions) + +@OrthogonalPredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.orthogonal(expr.parent), assumptions) + +@OrthogonalPredicate.register(Factorization) +def _(expr, assumptions): + return _Factorization(Q.orthogonal, expr, assumptions) + + +# UnitaryPredicate + +@UnitaryPredicate.register(MatMul) +def _(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.unitary(arg), assumptions) for arg in mmul.args) and + abs(factor) == 1): + return True + if any(ask(Q.invertible(arg), assumptions) is False + for arg in mmul.args): + return False + +@UnitaryPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if int_exp: + return ask(Q.unitary(base), assumptions) + return None + +@UnitaryPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if (not expr.is_square or + ask(Q.invertible(expr), assumptions) is False): + return False + if Q.unitary(expr) in conjuncts(assumptions): + return True + +@UnitaryPredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.unitary(expr.arg), assumptions) + +@UnitaryPredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.unitary(expr.parent), assumptions) + +@UnitaryPredicate.register_many(DFT, Identity) +def _(expr, assumptions): + return True + +@UnitaryPredicate.register(ZeroMatrix) +def _(expr, assumptions): + return False + +@UnitaryPredicate.register(Factorization) +def _(expr, assumptions): + return _Factorization(Q.unitary, expr, assumptions) + + +# FullRankPredicate + +@FullRankPredicate.register(MatMul) +def _(expr, assumptions): + if all(ask(Q.fullrank(arg), assumptions) for arg in expr.args): + return True + +@FullRankPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if int_exp and ask(~Q.negative(exp), assumptions): + return ask(Q.fullrank(base), assumptions) + return None + +@FullRankPredicate.register(Identity) +def _(expr, assumptions): + return True + +@FullRankPredicate.register(ZeroMatrix) +def _(expr, assumptions): + return False + +@FullRankPredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@FullRankPredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.fullrank(expr.arg), assumptions) + +@FullRankPredicate.register(MatrixSlice) +def _(expr, assumptions): + if ask(Q.orthogonal(expr.parent), assumptions): + return True + + +# PositiveDefinitePredicate + +@PositiveDefinitePredicate.register(MatMul) +def _(expr, assumptions): + factor, mmul = expr.as_coeff_mmul() + if (all(ask(Q.positive_definite(arg), assumptions) + for arg in mmul.args) and factor > 0): + return True + if (len(mmul.args) >= 2 + and mmul.args[0] == mmul.args[-1].T + and ask(Q.fullrank(mmul.args[0]), assumptions)): + return ask(Q.positive_definite( + MatMul(*mmul.args[1:-1])), assumptions) + +@PositiveDefinitePredicate.register(MatPow) +def _(expr, assumptions): + # a power of a positive definite matrix is positive definite + if ask(Q.positive_definite(expr.args[0]), assumptions): + return True + +@PositiveDefinitePredicate.register(MatAdd) +def _(expr, assumptions): + if all(ask(Q.positive_definite(arg), assumptions) + for arg in expr.args): + return True + +@PositiveDefinitePredicate.register(MatrixSymbol) +def _(expr, assumptions): + if not expr.is_square: + return False + if Q.positive_definite(expr) in conjuncts(assumptions): + return True + +@PositiveDefinitePredicate.register(Identity) +def _(expr, assumptions): + return True + +@PositiveDefinitePredicate.register(ZeroMatrix) +def _(expr, assumptions): + return False + +@PositiveDefinitePredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@PositiveDefinitePredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.positive_definite(expr.arg), assumptions) + +@PositiveDefinitePredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.positive_definite(expr.parent), assumptions) + + +# UpperTriangularPredicate + +@UpperTriangularPredicate.register(MatMul) +def _(expr, assumptions): + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.upper_triangular(m), assumptions) for m in matrices): + return True + +@UpperTriangularPredicate.register(MatAdd) +def _(expr, assumptions): + if all(ask(Q.upper_triangular(arg), assumptions) for arg in expr.args): + return True + +@UpperTriangularPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.upper_triangular(base), assumptions) + return None + +@UpperTriangularPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if Q.upper_triangular(expr) in conjuncts(assumptions): + return True + +@UpperTriangularPredicate.register_many(Identity, ZeroMatrix) +def _(expr, assumptions): + return True + +@UpperTriangularPredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@UpperTriangularPredicate.register(Transpose) +def _(expr, assumptions): + return ask(Q.lower_triangular(expr.arg), assumptions) + +@UpperTriangularPredicate.register(Inverse) +def _(expr, assumptions): + return ask(Q.upper_triangular(expr.arg), assumptions) + +@UpperTriangularPredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.upper_triangular(expr.parent), assumptions) + +@UpperTriangularPredicate.register(Factorization) +def _(expr, assumptions): + return _Factorization(Q.upper_triangular, expr, assumptions) + +# LowerTriangularPredicate + +@LowerTriangularPredicate.register(MatMul) +def _(expr, assumptions): + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.lower_triangular(m), assumptions) for m in matrices): + return True + +@LowerTriangularPredicate.register(MatAdd) +def _(expr, assumptions): + if all(ask(Q.lower_triangular(arg), assumptions) for arg in expr.args): + return True + +@LowerTriangularPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.lower_triangular(base), assumptions) + return None + +@LowerTriangularPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if Q.lower_triangular(expr) in conjuncts(assumptions): + return True + +@LowerTriangularPredicate.register_many(Identity, ZeroMatrix) +def _(expr, assumptions): + return True + +@LowerTriangularPredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@LowerTriangularPredicate.register(Transpose) +def _(expr, assumptions): + return ask(Q.upper_triangular(expr.arg), assumptions) + +@LowerTriangularPredicate.register(Inverse) +def _(expr, assumptions): + return ask(Q.lower_triangular(expr.arg), assumptions) + +@LowerTriangularPredicate.register(MatrixSlice) +def _(expr, assumptions): + if not expr.on_diag: + return None + else: + return ask(Q.lower_triangular(expr.parent), assumptions) + +@LowerTriangularPredicate.register(Factorization) +def _(expr, assumptions): + return _Factorization(Q.lower_triangular, expr, assumptions) + + +# DiagonalPredicate + +def _is_empty_or_1x1(expr): + return expr.shape in ((0, 0), (1, 1)) + +@DiagonalPredicate.register(MatMul) +def _(expr, assumptions): + if _is_empty_or_1x1(expr): + return True + factor, matrices = expr.as_coeff_matrices() + if all(ask(Q.diagonal(m), assumptions) for m in matrices): + return True + +@DiagonalPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.diagonal(base), assumptions) + return None + +@DiagonalPredicate.register(MatAdd) +def _(expr, assumptions): + if all(ask(Q.diagonal(arg), assumptions) for arg in expr.args): + return True + +@DiagonalPredicate.register(MatrixSymbol) +def _(expr, assumptions): + if _is_empty_or_1x1(expr): + return True + if Q.diagonal(expr) in conjuncts(assumptions): + return True + +@DiagonalPredicate.register(OneMatrix) +def _(expr, assumptions): + return expr.shape[0] == 1 and expr.shape[1] == 1 + +@DiagonalPredicate.register_many(Inverse, Transpose) +def _(expr, assumptions): + return ask(Q.diagonal(expr.arg), assumptions) + +@DiagonalPredicate.register(MatrixSlice) +def _(expr, assumptions): + if _is_empty_or_1x1(expr): + return True + if not expr.on_diag: + return None + else: + return ask(Q.diagonal(expr.parent), assumptions) + +@DiagonalPredicate.register_many(DiagonalMatrix, DiagMatrix, Identity, ZeroMatrix) +def _(expr, assumptions): + return True + +@DiagonalPredicate.register(Factorization) +def _(expr, assumptions): + return _Factorization(Q.diagonal, expr, assumptions) + + +# IntegerElementsPredicate + +def BM_elements(predicate, expr, assumptions): + """ Block Matrix elements. """ + return all(ask(predicate(b), assumptions) for b in expr.blocks) + +def MS_elements(predicate, expr, assumptions): + """ Matrix Slice elements. """ + return ask(predicate(expr.parent), assumptions) + +def MatMul_elements(matrix_predicate, scalar_predicate, expr, assumptions): + d = sift(expr.args, lambda x: isinstance(x, MatrixExpr)) + factors, matrices = d[False], d[True] + return fuzzy_and([ + test_closed_group(Basic(*factors), assumptions, scalar_predicate), + test_closed_group(Basic(*matrices), assumptions, matrix_predicate)]) + + +@IntegerElementsPredicate.register_many(Determinant, HadamardProduct, MatAdd, + Trace, Transpose) +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.integer_elements) + +@IntegerElementsPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + if exp.is_negative == False: + return ask(Q.integer_elements(base), assumptions) + return None + +@IntegerElementsPredicate.register_many(Identity, OneMatrix, ZeroMatrix) +def _(expr, assumptions): + return True + +@IntegerElementsPredicate.register(MatMul) +def _(expr, assumptions): + return MatMul_elements(Q.integer_elements, Q.integer, expr, assumptions) + +@IntegerElementsPredicate.register(MatrixSlice) +def _(expr, assumptions): + return MS_elements(Q.integer_elements, expr, assumptions) + +@IntegerElementsPredicate.register(BlockMatrix) +def _(expr, assumptions): + return BM_elements(Q.integer_elements, expr, assumptions) + + +# RealElementsPredicate + +@RealElementsPredicate.register_many(Determinant, Factorization, HadamardProduct, + MatAdd, Trace, Transpose) +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.real_elements) + +@RealElementsPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.real_elements(base), assumptions) + return None + +@RealElementsPredicate.register(MatMul) +def _(expr, assumptions): + return MatMul_elements(Q.real_elements, Q.real, expr, assumptions) + +@RealElementsPredicate.register(MatrixSlice) +def _(expr, assumptions): + return MS_elements(Q.real_elements, expr, assumptions) + +@RealElementsPredicate.register(BlockMatrix) +def _(expr, assumptions): + return BM_elements(Q.real_elements, expr, assumptions) + + +# ComplexElementsPredicate + +@ComplexElementsPredicate.register_many(Determinant, Factorization, HadamardProduct, + Inverse, MatAdd, Trace, Transpose) +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.complex_elements) + +@ComplexElementsPredicate.register(MatPow) +def _(expr, assumptions): + # only for integer powers + base, exp = expr.args + int_exp = ask(Q.integer(exp), assumptions) + if not int_exp: + return None + non_negative = ask(~Q.negative(exp), assumptions) + if (non_negative or non_negative == False + and ask(Q.invertible(base), assumptions)): + return ask(Q.complex_elements(base), assumptions) + return None + +@ComplexElementsPredicate.register(MatMul) +def _(expr, assumptions): + return MatMul_elements(Q.complex_elements, Q.complex, expr, assumptions) + +@ComplexElementsPredicate.register(MatrixSlice) +def _(expr, assumptions): + return MS_elements(Q.complex_elements, expr, assumptions) + +@ComplexElementsPredicate.register(BlockMatrix) +def _(expr, assumptions): + return BM_elements(Q.complex_elements, expr, assumptions) + +@ComplexElementsPredicate.register(DFT) +def _(expr, assumptions): + return True diff --git a/lib/python3.12/site-packages/sympy/assumptions/handlers/ntheory.py b/lib/python3.12/site-packages/sympy/assumptions/handlers/ntheory.py new file mode 100644 index 0000000000000000000000000000000000000000..ccb91f726e2ee5c10d915725f60f5093934d4e7b --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/handlers/ntheory.py @@ -0,0 +1,269 @@ +""" +Handlers for keys related to number theory: prime, even, odd, etc. +""" + +from sympy.assumptions import Q, ask +from sympy.core import Add, Basic, Expr, Float, Mul, Pow, S +from sympy.core.numbers import (ImaginaryUnit, Infinity, Integer, NaN, + NegativeInfinity, NumberSymbol, Rational, int_valued) +from sympy.functions import Abs, im, re +from sympy.ntheory import isprime + +from sympy.multipledispatch import MDNotImplementedError + +from ..predicates.ntheory import (PrimePredicate, CompositePredicate, + EvenPredicate, OddPredicate) + + +# PrimePredicate + +def _PrimePredicate_number(expr, assumptions): + # helper method + exact = not expr.atoms(Float) + try: + i = int(expr.round()) + if (expr - i).equals(0) is False: + raise TypeError + except TypeError: + return False + if exact: + return isprime(i) + # when not exact, we won't give a True or False + # since the number represents an approximate value + +@PrimePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_prime + if ret is None: + raise MDNotImplementedError + return ret + +@PrimePredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + return _PrimePredicate_number(expr, assumptions) + +@PrimePredicate.register(Mul) +def _(expr, assumptions): + if expr.is_number: + return _PrimePredicate_number(expr, assumptions) + for arg in expr.args: + if not ask(Q.integer(arg), assumptions): + return None + for arg in expr.args: + if arg.is_number and arg.is_composite: + return False + +@PrimePredicate.register(Pow) +def _(expr, assumptions): + """ + Integer**Integer -> !Prime + """ + if expr.is_number: + return _PrimePredicate_number(expr, assumptions) + if ask(Q.integer(expr.exp), assumptions) and \ + ask(Q.integer(expr.base), assumptions): + return False + +@PrimePredicate.register(Integer) +def _(expr, assumptions): + return isprime(expr) + +@PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit) +def _(expr, assumptions): + return False + +@PrimePredicate.register(Float) +def _(expr, assumptions): + return _PrimePredicate_number(expr, assumptions) + +@PrimePredicate.register(NumberSymbol) +def _(expr, assumptions): + return _PrimePredicate_number(expr, assumptions) + +@PrimePredicate.register(NaN) +def _(expr, assumptions): + return None + + +# CompositePredicate + +@CompositePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_composite + if ret is None: + raise MDNotImplementedError + return ret + +@CompositePredicate.register(Basic) +def _(expr, assumptions): + _positive = ask(Q.positive(expr), assumptions) + if _positive: + _integer = ask(Q.integer(expr), assumptions) + if _integer: + _prime = ask(Q.prime(expr), assumptions) + if _prime is None: + return + # Positive integer which is not prime is not + # necessarily composite + if expr.equals(1): + return False + return not _prime + else: + return _integer + else: + return _positive + + +# EvenPredicate + +def _EvenPredicate_number(expr, assumptions): + # helper method + if isinstance(expr, (float, Float)): + if int_valued(expr): + return None + return False + try: + i = int(expr.round()) + except TypeError: + return False + if not (expr - i).equals(0): + return False + return i % 2 == 0 + +@EvenPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_even + if ret is None: + raise MDNotImplementedError + return ret + +@EvenPredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + return _EvenPredicate_number(expr, assumptions) + +@EvenPredicate.register(Mul) +def _(expr, assumptions): + """ + Even * Integer -> Even + Even * Odd -> Even + Integer * Odd -> ? + Odd * Odd -> Odd + Even * Even -> Even + Integer * Integer -> Even if Integer + Integer = Odd + otherwise -> ? + """ + if expr.is_number: + return _EvenPredicate_number(expr, assumptions) + even, odd, irrational, acc = False, 0, False, 1 + for arg in expr.args: + # check for all integers and at least one even + if ask(Q.integer(arg), assumptions): + if ask(Q.even(arg), assumptions): + even = True + elif ask(Q.odd(arg), assumptions): + odd += 1 + elif not even and acc != 1: + if ask(Q.odd(acc + arg), assumptions): + even = True + elif ask(Q.irrational(arg), assumptions): + # one irrational makes the result False + # two makes it undefined + if irrational: + break + irrational = True + else: + break + acc = arg + else: + if irrational: + return False + if even: + return True + if odd == len(expr.args): + return False + +@EvenPredicate.register(Add) +def _(expr, assumptions): + """ + Even + Odd -> Odd + Even + Even -> Even + Odd + Odd -> Even + + """ + if expr.is_number: + return _EvenPredicate_number(expr, assumptions) + _result = True + for arg in expr.args: + if ask(Q.even(arg), assumptions): + pass + elif ask(Q.odd(arg), assumptions): + _result = not _result + else: + break + else: + return _result + +@EvenPredicate.register(Pow) +def _(expr, assumptions): + if expr.is_number: + return _EvenPredicate_number(expr, assumptions) + if ask(Q.integer(expr.exp), assumptions): + if ask(Q.positive(expr.exp), assumptions): + return ask(Q.even(expr.base), assumptions) + elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions): + return False + elif expr.base is S.NegativeOne: + return False + +@EvenPredicate.register(Integer) +def _(expr, assumptions): + return not bool(expr.p & 1) + +@EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit) +def _(expr, assumptions): + return False + +@EvenPredicate.register(NumberSymbol) +def _(expr, assumptions): + return _EvenPredicate_number(expr, assumptions) + +@EvenPredicate.register(Abs) +def _(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return ask(Q.even(expr.args[0]), assumptions) + +@EvenPredicate.register(re) +def _(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return ask(Q.even(expr.args[0]), assumptions) + +@EvenPredicate.register(im) +def _(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return True + +@EvenPredicate.register(NaN) +def _(expr, assumptions): + return None + + +# OddPredicate + +@OddPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_odd + if ret is None: + raise MDNotImplementedError + return ret + +@OddPredicate.register(Basic) +def _(expr, assumptions): + _integer = ask(Q.integer(expr), assumptions) + if _integer: + _even = ask(Q.even(expr), assumptions) + if _even is None: + return None + return not _even + return _integer diff --git a/lib/python3.12/site-packages/sympy/assumptions/handlers/order.py b/lib/python3.12/site-packages/sympy/assumptions/handlers/order.py new file mode 100644 index 0000000000000000000000000000000000000000..f4a5378c20a9fcf152914fc5cc9488583f2e39a3 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/handlers/order.py @@ -0,0 +1,436 @@ +""" +Handlers related to order relations: positive, negative, etc. +""" + +from sympy.assumptions import Q, ask +from sympy.core import Add, Basic, Expr, Mul, Pow +from sympy.core.logic import fuzzy_not, fuzzy_and, fuzzy_or +from sympy.core.numbers import E, ImaginaryUnit, NaN, I, pi +from sympy.functions import Abs, acos, acot, asin, atan, exp, factorial, log +from sympy.matrices import Determinant, Trace +from sympy.matrices.expressions.matexpr import MatrixElement + +from sympy.multipledispatch import MDNotImplementedError + +from ..predicates.order import (NegativePredicate, NonNegativePredicate, + NonZeroPredicate, ZeroPredicate, NonPositivePredicate, PositivePredicate, + ExtendedNegativePredicate, ExtendedNonNegativePredicate, + ExtendedNonPositivePredicate, ExtendedNonZeroPredicate, + ExtendedPositivePredicate,) + + +# NegativePredicate + +def _NegativePredicate_number(expr, assumptions): + r, i = expr.as_real_imag() + # If the imaginary part can symbolically be shown to be zero then + # we just evaluate the real part; otherwise we evaluate the imaginary + # part to see if it actually evaluates to zero and if it does then + # we make the comparison between the real part and zero. + if not i: + r = r.evalf(2) + if r._prec != 1: + return r < 0 + else: + i = i.evalf(2) + if i._prec != 1: + if i != 0: + return False + r = r.evalf(2) + if r._prec != 1: + return r < 0 + +@NegativePredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + return _NegativePredicate_number(expr, assumptions) + +@NegativePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_negative + if ret is None: + raise MDNotImplementedError + return ret + +@NegativePredicate.register(Add) +def _(expr, assumptions): + """ + Positive + Positive -> Positive, + Negative + Negative -> Negative + """ + if expr.is_number: + return _NegativePredicate_number(expr, assumptions) + + r = ask(Q.real(expr), assumptions) + if r is not True: + return r + + nonpos = 0 + for arg in expr.args: + if ask(Q.negative(arg), assumptions) is not True: + if ask(Q.positive(arg), assumptions) is False: + nonpos += 1 + else: + break + else: + if nonpos < len(expr.args): + return True + +@NegativePredicate.register(Mul) +def _(expr, assumptions): + if expr.is_number: + return _NegativePredicate_number(expr, assumptions) + result = None + for arg in expr.args: + if result is None: + result = False + if ask(Q.negative(arg), assumptions): + result = not result + elif ask(Q.positive(arg), assumptions): + pass + else: + return + return result + +@NegativePredicate.register(Pow) +def _(expr, assumptions): + """ + Real ** Even -> NonNegative + Real ** Odd -> same_as_base + NonNegative ** Positive -> NonNegative + """ + if expr.base == E: + # Exponential is always positive: + if ask(Q.real(expr.exp), assumptions): + return False + return + + if expr.is_number: + return _NegativePredicate_number(expr, assumptions) + if ask(Q.real(expr.base), assumptions): + if ask(Q.positive(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + return False + if ask(Q.even(expr.exp), assumptions): + return False + if ask(Q.odd(expr.exp), assumptions): + return ask(Q.negative(expr.base), assumptions) + +@NegativePredicate.register_many(Abs, ImaginaryUnit) +def _(expr, assumptions): + return False + +@NegativePredicate.register(exp) +def _(expr, assumptions): + if ask(Q.real(expr.exp), assumptions): + return False + raise MDNotImplementedError + + +# NonNegativePredicate + +@NonNegativePredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + notnegative = fuzzy_not(_NegativePredicate_number(expr, assumptions)) + if notnegative: + return ask(Q.real(expr), assumptions) + else: + return notnegative + +@NonNegativePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_nonnegative + if ret is None: + raise MDNotImplementedError + return ret + + +# NonZeroPredicate + +@NonZeroPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_nonzero + if ret is None: + raise MDNotImplementedError + return ret + +@NonZeroPredicate.register(Basic) +def _(expr, assumptions): + if ask(Q.real(expr)) is False: + return False + if expr.is_number: + # if there are no symbols just evalf + i = expr.evalf(2) + def nonz(i): + if i._prec != 1: + return i != 0 + return fuzzy_or(nonz(i) for i in i.as_real_imag()) + +@NonZeroPredicate.register(Add) +def _(expr, assumptions): + if all(ask(Q.positive(x), assumptions) for x in expr.args) \ + or all(ask(Q.negative(x), assumptions) for x in expr.args): + return True + +@NonZeroPredicate.register(Mul) +def _(expr, assumptions): + for arg in expr.args: + result = ask(Q.nonzero(arg), assumptions) + if result: + continue + return result + return True + +@NonZeroPredicate.register(Pow) +def _(expr, assumptions): + return ask(Q.nonzero(expr.base), assumptions) + +@NonZeroPredicate.register(Abs) +def _(expr, assumptions): + return ask(Q.nonzero(expr.args[0]), assumptions) + +@NonZeroPredicate.register(NaN) +def _(expr, assumptions): + return None + + +# ZeroPredicate + +@ZeroPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_zero + if ret is None: + raise MDNotImplementedError + return ret + +@ZeroPredicate.register(Basic) +def _(expr, assumptions): + return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), + ask(Q.real(expr), assumptions)]) + +@ZeroPredicate.register(Mul) +def _(expr, assumptions): + # TODO: This should be deducible from the nonzero handler + return fuzzy_or(ask(Q.zero(arg), assumptions) for arg in expr.args) + + +# NonPositivePredicate + +@NonPositivePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_nonpositive + if ret is None: + raise MDNotImplementedError + return ret + +@NonPositivePredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + notpositive = fuzzy_not(_PositivePredicate_number(expr, assumptions)) + if notpositive: + return ask(Q.real(expr), assumptions) + else: + return notpositive + + +# PositivePredicate + +def _PositivePredicate_number(expr, assumptions): + r, i = expr.as_real_imag() + # If the imaginary part can symbolically be shown to be zero then + # we just evaluate the real part; otherwise we evaluate the imaginary + # part to see if it actually evaluates to zero and if it does then + # we make the comparison between the real part and zero. + if not i: + r = r.evalf(2) + if r._prec != 1: + return r > 0 + else: + i = i.evalf(2) + if i._prec != 1: + if i != 0: + return False + r = r.evalf(2) + if r._prec != 1: + return r > 0 + +@PositivePredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_positive + if ret is None: + raise MDNotImplementedError + return ret + +@PositivePredicate.register(Basic) +def _(expr, assumptions): + if expr.is_number: + return _PositivePredicate_number(expr, assumptions) + +@PositivePredicate.register(Mul) +def _(expr, assumptions): + if expr.is_number: + return _PositivePredicate_number(expr, assumptions) + result = True + for arg in expr.args: + if ask(Q.positive(arg), assumptions): + continue + elif ask(Q.negative(arg), assumptions): + result = result ^ True + else: + return + return result + +@PositivePredicate.register(Add) +def _(expr, assumptions): + if expr.is_number: + return _PositivePredicate_number(expr, assumptions) + + r = ask(Q.real(expr), assumptions) + if r is not True: + return r + + nonneg = 0 + for arg in expr.args: + if ask(Q.positive(arg), assumptions) is not True: + if ask(Q.negative(arg), assumptions) is False: + nonneg += 1 + else: + break + else: + if nonneg < len(expr.args): + return True + +@PositivePredicate.register(Pow) +def _(expr, assumptions): + if expr.base == E: + if ask(Q.real(expr.exp), assumptions): + return True + if ask(Q.imaginary(expr.exp), assumptions): + return ask(Q.even(expr.exp/(I*pi)), assumptions) + return + + if expr.is_number: + return _PositivePredicate_number(expr, assumptions) + if ask(Q.positive(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + return True + if ask(Q.negative(expr.base), assumptions): + if ask(Q.even(expr.exp), assumptions): + return True + if ask(Q.odd(expr.exp), assumptions): + return False + +@PositivePredicate.register(exp) +def _(expr, assumptions): + if ask(Q.real(expr.exp), assumptions): + return True + if ask(Q.imaginary(expr.exp), assumptions): + return ask(Q.even(expr.exp/(I*pi)), assumptions) + +@PositivePredicate.register(log) +def _(expr, assumptions): + r = ask(Q.real(expr.args[0]), assumptions) + if r is not True: + return r + if ask(Q.positive(expr.args[0] - 1), assumptions): + return True + if ask(Q.negative(expr.args[0] - 1), assumptions): + return False + +@PositivePredicate.register(factorial) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.integer(x) & Q.positive(x), assumptions): + return True + +@PositivePredicate.register(ImaginaryUnit) +def _(expr, assumptions): + return False + +@PositivePredicate.register(Abs) +def _(expr, assumptions): + return ask(Q.nonzero(expr), assumptions) + +@PositivePredicate.register(Trace) +def _(expr, assumptions): + if ask(Q.positive_definite(expr.arg), assumptions): + return True + +@PositivePredicate.register(Determinant) +def _(expr, assumptions): + if ask(Q.positive_definite(expr.arg), assumptions): + return True + +@PositivePredicate.register(MatrixElement) +def _(expr, assumptions): + if (expr.i == expr.j + and ask(Q.positive_definite(expr.parent), assumptions)): + return True + +@PositivePredicate.register(atan) +def _(expr, assumptions): + return ask(Q.positive(expr.args[0]), assumptions) + +@PositivePredicate.register(asin) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.positive(x) & Q.nonpositive(x - 1), assumptions): + return True + if ask(Q.negative(x) & Q.nonnegative(x + 1), assumptions): + return False + +@PositivePredicate.register(acos) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.nonpositive(x - 1) & Q.nonnegative(x + 1), assumptions): + return True + +@PositivePredicate.register(acot) +def _(expr, assumptions): + return ask(Q.real(expr.args[0]), assumptions) + +@PositivePredicate.register(NaN) +def _(expr, assumptions): + return None + + +# ExtendedNegativePredicate + +@ExtendedNegativePredicate.register(object) +def _(expr, assumptions): + return ask(Q.negative(expr) | Q.negative_infinite(expr), assumptions) + + +# ExtendedPositivePredicate + +@ExtendedPositivePredicate.register(object) +def _(expr, assumptions): + return ask(Q.positive(expr) | Q.positive_infinite(expr), assumptions) + + +# ExtendedNonZeroPredicate + +@ExtendedNonZeroPredicate.register(object) +def _(expr, assumptions): + return ask( + Q.negative_infinite(expr) | Q.negative(expr) | Q.positive(expr) | Q.positive_infinite(expr), + assumptions) + + +# ExtendedNonPositivePredicate + +@ExtendedNonPositivePredicate.register(object) +def _(expr, assumptions): + return ask( + Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr), + assumptions) + + +# ExtendedNonNegativePredicate + +@ExtendedNonNegativePredicate.register(object) +def _(expr, assumptions): + return ask( + Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr), + assumptions) diff --git a/lib/python3.12/site-packages/sympy/assumptions/handlers/sets.py b/lib/python3.12/site-packages/sympy/assumptions/handlers/sets.py new file mode 100644 index 0000000000000000000000000000000000000000..b53bcfedef30681ea4450c6dad9120bc2ea9016e --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/handlers/sets.py @@ -0,0 +1,772 @@ +""" +Handlers for predicates related to set membership: integer, rational, etc. +""" + +from sympy.assumptions import Q, ask +from sympy.core import Add, Basic, Expr, Mul, Pow, S +from sympy.core.numbers import (AlgebraicNumber, ComplexInfinity, Exp1, Float, + GoldenRatio, ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity, + Number, NumberSymbol, Pi, pi, Rational, TribonacciConstant, E) +from sympy.core.logic import fuzzy_bool +from sympy.functions import (Abs, acos, acot, asin, atan, cos, cot, exp, im, + log, re, sin, tan) +from sympy.core.numbers import I +from sympy.core.relational import Eq +from sympy.functions.elementary.complexes import conjugate +from sympy.matrices import Determinant, MatrixBase, Trace +from sympy.matrices.expressions.matexpr import MatrixElement + +from sympy.multipledispatch import MDNotImplementedError + +from .common import test_closed_group +from ..predicates.sets import (IntegerPredicate, RationalPredicate, + IrrationalPredicate, RealPredicate, ExtendedRealPredicate, + HermitianPredicate, ComplexPredicate, ImaginaryPredicate, + AntihermitianPredicate, AlgebraicPredicate) + + +# IntegerPredicate + +def _IntegerPredicate_number(expr, assumptions): + # helper function + try: + i = int(expr.round()) + if not (expr - i).equals(0): + raise TypeError + return True + except TypeError: + return False + +@IntegerPredicate.register_many(int, Integer) # type:ignore +def _(expr, assumptions): + return True + +@IntegerPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity, + NegativeInfinity, Pi, Rational, TribonacciConstant) +def _(expr, assumptions): + return False + +@IntegerPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_integer + if ret is None: + raise MDNotImplementedError + return ret + +@IntegerPredicate.register_many(Add, Pow) +def _(expr, assumptions): + """ + * Integer + Integer -> Integer + * Integer + !Integer -> !Integer + * !Integer + !Integer -> ? + """ + if expr.is_number: + return _IntegerPredicate_number(expr, assumptions) + return test_closed_group(expr, assumptions, Q.integer) + +@IntegerPredicate.register(Mul) +def _(expr, assumptions): + """ + * Integer*Integer -> Integer + * Integer*Irrational -> !Integer + * Odd/Even -> !Integer + * Integer*Rational -> ? + """ + if expr.is_number: + return _IntegerPredicate_number(expr, assumptions) + _output = True + for arg in expr.args: + if not ask(Q.integer(arg), assumptions): + if arg.is_Rational: + if arg.q == 2: + return ask(Q.even(2*expr), assumptions) + if ~(arg.q & 1): + return None + elif ask(Q.irrational(arg), assumptions): + if _output: + _output = False + else: + return + else: + return + + return _output + +@IntegerPredicate.register(Abs) +def _(expr, assumptions): + return ask(Q.integer(expr.args[0]), assumptions) + +@IntegerPredicate.register_many(Determinant, MatrixElement, Trace) +def _(expr, assumptions): + return ask(Q.integer_elements(expr.args[0]), assumptions) + + +# RationalPredicate + +@RationalPredicate.register(Rational) +def _(expr, assumptions): + return True + +@RationalPredicate.register(Float) +def _(expr, assumptions): + return None + +@RationalPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity, + NegativeInfinity, Pi, TribonacciConstant) +def _(expr, assumptions): + return False + +@RationalPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_rational + if ret is None: + raise MDNotImplementedError + return ret + +@RationalPredicate.register_many(Add, Mul) +def _(expr, assumptions): + """ + * Rational + Rational -> Rational + * Rational + !Rational -> !Rational + * !Rational + !Rational -> ? + """ + if expr.is_number: + if expr.as_real_imag()[1]: + return False + return test_closed_group(expr, assumptions, Q.rational) + +@RationalPredicate.register(Pow) +def _(expr, assumptions): + """ + * Rational ** Integer -> Rational + * Irrational ** Rational -> Irrational + * Rational ** Irrational -> ? + """ + if expr.base == E: + x = expr.exp + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x), assumptions) + return + + if ask(Q.integer(expr.exp), assumptions): + return ask(Q.rational(expr.base), assumptions) + elif ask(Q.rational(expr.exp), assumptions): + if ask(Q.prime(expr.base), assumptions): + return False + +@RationalPredicate.register_many(asin, atan, cos, sin, tan) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x), assumptions) + +@RationalPredicate.register(exp) +def _(expr, assumptions): + x = expr.exp + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x), assumptions) + +@RationalPredicate.register_many(acot, cot) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return False + +@RationalPredicate.register_many(acos, log) +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.rational(x), assumptions): + return ask(~Q.nonzero(x - 1), assumptions) + + +# IrrationalPredicate + +@IrrationalPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_irrational + if ret is None: + raise MDNotImplementedError + return ret + +@IrrationalPredicate.register(Basic) +def _(expr, assumptions): + _real = ask(Q.real(expr), assumptions) + if _real: + _rational = ask(Q.rational(expr), assumptions) + if _rational is None: + return None + return not _rational + else: + return _real + + +# RealPredicate + +def _RealPredicate_number(expr, assumptions): + # let as_real_imag() work first since the expression may + # be simpler to evaluate + i = expr.as_real_imag()[1].evalf(2) + if i._prec != 1: + return not i + # allow None to be returned if we couldn't show for sure + # that i was 0 + +@RealPredicate.register_many(Abs, Exp1, Float, GoldenRatio, im, Pi, Rational, + re, TribonacciConstant) +def _(expr, assumptions): + return True + +@RealPredicate.register_many(ImaginaryUnit, Infinity, NegativeInfinity) +def _(expr, assumptions): + return False + +@RealPredicate.register(Expr) +def _(expr, assumptions): + ret = expr.is_real + if ret is None: + raise MDNotImplementedError + return ret + +@RealPredicate.register(Add) +def _(expr, assumptions): + """ + * Real + Real -> Real + * Real + (Complex & !Real) -> !Real + """ + if expr.is_number: + return _RealPredicate_number(expr, assumptions) + return test_closed_group(expr, assumptions, Q.real) + +@RealPredicate.register(Mul) +def _(expr, assumptions): + """ + * Real*Real -> Real + * Real*Imaginary -> !Real + * Imaginary*Imaginary -> Real + """ + if expr.is_number: + return _RealPredicate_number(expr, assumptions) + result = True + for arg in expr.args: + if ask(Q.real(arg), assumptions): + pass + elif ask(Q.imaginary(arg), assumptions): + result = result ^ True + else: + break + else: + return result + +@RealPredicate.register(Pow) +def _(expr, assumptions): + """ + * Real**Integer -> Real + * Positive**Real -> Real + * Real**(Integer/Even) -> Real if base is nonnegative + * Real**(Integer/Odd) -> Real + * Imaginary**(Integer/Even) -> Real + * Imaginary**(Integer/Odd) -> not Real + * Imaginary**Real -> ? since Real could be 0 (giving real) + or 1 (giving imaginary) + * b**Imaginary -> Real if log(b) is imaginary and b != 0 + and exponent != integer multiple of + I*pi/log(b) + * Real**Real -> ? e.g. sqrt(-1) is imaginary and + sqrt(2) is not + """ + if expr.is_number: + return _RealPredicate_number(expr, assumptions) + + if expr.base == E: + return ask( + Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions + ) + + if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E): + if ask(Q.imaginary(expr.base.exp), assumptions): + if ask(Q.imaginary(expr.exp), assumptions): + return True + # If the i = (exp's arg)/(I*pi) is an integer or half-integer + # multiple of I*pi then 2*i will be an integer. In addition, + # exp(i*I*pi) = (-1)**i so the overall realness of the expr + # can be determined by replacing exp(i*I*pi) with (-1)**i. + i = expr.base.exp/I/pi + if ask(Q.integer(2*i), assumptions): + return ask(Q.real((S.NegativeOne**i)**expr.exp), assumptions) + return + + if ask(Q.imaginary(expr.base), assumptions): + if ask(Q.integer(expr.exp), assumptions): + odd = ask(Q.odd(expr.exp), assumptions) + if odd is not None: + return not odd + return + + if ask(Q.imaginary(expr.exp), assumptions): + imlog = ask(Q.imaginary(log(expr.base)), assumptions) + if imlog is not None: + # I**i -> real, log(I) is imag; + # (2*I)**i -> complex, log(2*I) is not imag + return imlog + + if ask(Q.real(expr.base), assumptions): + if ask(Q.real(expr.exp), assumptions): + if expr.exp.is_Rational and \ + ask(Q.even(expr.exp.q), assumptions): + return ask(Q.positive(expr.base), assumptions) + elif ask(Q.integer(expr.exp), assumptions): + return True + elif ask(Q.positive(expr.base), assumptions): + return True + elif ask(Q.negative(expr.base), assumptions): + return False + +@RealPredicate.register_many(cos, sin) +def _(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + return True + +@RealPredicate.register(exp) +def _(expr, assumptions): + return ask( + Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions + ) + +@RealPredicate.register(log) +def _(expr, assumptions): + return ask(Q.positive(expr.args[0]), assumptions) + +@RealPredicate.register_many(Determinant, MatrixElement, Trace) +def _(expr, assumptions): + return ask(Q.real_elements(expr.args[0]), assumptions) + + +# ExtendedRealPredicate + +@ExtendedRealPredicate.register(object) +def _(expr, assumptions): + return ask(Q.negative_infinite(expr) + | Q.negative(expr) + | Q.zero(expr) + | Q.positive(expr) + | Q.positive_infinite(expr), + assumptions) + +@ExtendedRealPredicate.register_many(Infinity, NegativeInfinity) +def _(expr, assumptions): + return True + +@ExtendedRealPredicate.register_many(Add, Mul, Pow) # type:ignore +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.extended_real) + + +# HermitianPredicate + +@HermitianPredicate.register(object) # type:ignore +def _(expr, assumptions): + if isinstance(expr, MatrixBase): + return None + return ask(Q.real(expr), assumptions) + +@HermitianPredicate.register(Add) # type:ignore +def _(expr, assumptions): + """ + * Hermitian + Hermitian -> Hermitian + * Hermitian + !Hermitian -> !Hermitian + """ + if expr.is_number: + raise MDNotImplementedError + return test_closed_group(expr, assumptions, Q.hermitian) + +@HermitianPredicate.register(Mul) # type:ignore +def _(expr, assumptions): + """ + As long as there is at most only one noncommutative term: + + * Hermitian*Hermitian -> Hermitian + * Hermitian*Antihermitian -> !Hermitian + * Antihermitian*Antihermitian -> Hermitian + """ + if expr.is_number: + raise MDNotImplementedError + nccount = 0 + result = True + for arg in expr.args: + if ask(Q.antihermitian(arg), assumptions): + result = result ^ True + elif not ask(Q.hermitian(arg), assumptions): + break + if ask(~Q.commutative(arg), assumptions): + nccount += 1 + if nccount > 1: + break + else: + return result + +@HermitianPredicate.register(Pow) # type:ignore +def _(expr, assumptions): + """ + * Hermitian**Integer -> Hermitian + """ + if expr.is_number: + raise MDNotImplementedError + if expr.base == E: + if ask(Q.hermitian(expr.exp), assumptions): + return True + raise MDNotImplementedError + if ask(Q.hermitian(expr.base), assumptions): + if ask(Q.integer(expr.exp), assumptions): + return True + raise MDNotImplementedError + +@HermitianPredicate.register_many(cos, sin) # type:ignore +def _(expr, assumptions): + if ask(Q.hermitian(expr.args[0]), assumptions): + return True + raise MDNotImplementedError + +@HermitianPredicate.register(exp) # type:ignore +def _(expr, assumptions): + if ask(Q.hermitian(expr.exp), assumptions): + return True + raise MDNotImplementedError + +@HermitianPredicate.register(MatrixBase) # type:ignore +def _(mat, assumptions): + rows, cols = mat.shape + ret_val = True + for i in range(rows): + for j in range(i, cols): + cond = fuzzy_bool(Eq(mat[i, j], conjugate(mat[j, i]))) + if cond is None: + ret_val = None + if cond == False: + return False + if ret_val is None: + raise MDNotImplementedError + return ret_val + + +# ComplexPredicate + +@ComplexPredicate.register_many(Abs, cos, exp, im, ImaginaryUnit, log, Number, # type:ignore + NumberSymbol, re, sin) +def _(expr, assumptions): + return True + +@ComplexPredicate.register_many(Infinity, NegativeInfinity) # type:ignore +def _(expr, assumptions): + return False + +@ComplexPredicate.register(Expr) # type:ignore +def _(expr, assumptions): + ret = expr.is_complex + if ret is None: + raise MDNotImplementedError + return ret + +@ComplexPredicate.register_many(Add, Mul) # type:ignore +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.complex) + +@ComplexPredicate.register(Pow) # type:ignore +def _(expr, assumptions): + if expr.base == E: + return True + return test_closed_group(expr, assumptions, Q.complex) + +@ComplexPredicate.register_many(Determinant, MatrixElement, Trace) # type:ignore +def _(expr, assumptions): + return ask(Q.complex_elements(expr.args[0]), assumptions) + +@ComplexPredicate.register(NaN) # type:ignore +def _(expr, assumptions): + return None + + +# ImaginaryPredicate + +def _Imaginary_number(expr, assumptions): + # let as_real_imag() work first since the expression may + # be simpler to evaluate + r = expr.as_real_imag()[0].evalf(2) + if r._prec != 1: + return not r + # allow None to be returned if we couldn't show for sure + # that r was 0 + +@ImaginaryPredicate.register(ImaginaryUnit) # type:ignore +def _(expr, assumptions): + return True + +@ImaginaryPredicate.register(Expr) # type:ignore +def _(expr, assumptions): + ret = expr.is_imaginary + if ret is None: + raise MDNotImplementedError + return ret + +@ImaginaryPredicate.register(Add) # type:ignore +def _(expr, assumptions): + """ + * Imaginary + Imaginary -> Imaginary + * Imaginary + Complex -> ? + * Imaginary + Real -> !Imaginary + """ + if expr.is_number: + return _Imaginary_number(expr, assumptions) + + reals = 0 + for arg in expr.args: + if ask(Q.imaginary(arg), assumptions): + pass + elif ask(Q.real(arg), assumptions): + reals += 1 + else: + break + else: + if reals == 0: + return True + if reals in (1, len(expr.args)): + # two reals could sum 0 thus giving an imaginary + return False + +@ImaginaryPredicate.register(Mul) # type:ignore +def _(expr, assumptions): + """ + * Real*Imaginary -> Imaginary + * Imaginary*Imaginary -> Real + """ + if expr.is_number: + return _Imaginary_number(expr, assumptions) + result = False + reals = 0 + for arg in expr.args: + if ask(Q.imaginary(arg), assumptions): + result = result ^ True + elif not ask(Q.real(arg), assumptions): + break + else: + if reals == len(expr.args): + return False + return result + +@ImaginaryPredicate.register(Pow) # type:ignore +def _(expr, assumptions): + """ + * Imaginary**Odd -> Imaginary + * Imaginary**Even -> Real + * b**Imaginary -> !Imaginary if exponent is an integer + multiple of I*pi/log(b) + * Imaginary**Real -> ? + * Positive**Real -> Real + * Negative**Integer -> Real + * Negative**(Integer/2) -> Imaginary + * Negative**Real -> not Imaginary if exponent is not Rational + """ + if expr.is_number: + return _Imaginary_number(expr, assumptions) + + if expr.base == E: + a = expr.exp/I/pi + return ask(Q.integer(2*a) & ~Q.integer(a), assumptions) + + if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E): + if ask(Q.imaginary(expr.base.exp), assumptions): + if ask(Q.imaginary(expr.exp), assumptions): + return False + i = expr.base.exp/I/pi + if ask(Q.integer(2*i), assumptions): + return ask(Q.imaginary((S.NegativeOne**i)**expr.exp), assumptions) + + if ask(Q.imaginary(expr.base), assumptions): + if ask(Q.integer(expr.exp), assumptions): + odd = ask(Q.odd(expr.exp), assumptions) + if odd is not None: + return odd + return + + if ask(Q.imaginary(expr.exp), assumptions): + imlog = ask(Q.imaginary(log(expr.base)), assumptions) + if imlog is not None: + # I**i -> real; (2*I)**i -> complex ==> not imaginary + return False + + if ask(Q.real(expr.base) & Q.real(expr.exp), assumptions): + if ask(Q.positive(expr.base), assumptions): + return False + else: + rat = ask(Q.rational(expr.exp), assumptions) + if not rat: + return rat + if ask(Q.integer(expr.exp), assumptions): + return False + else: + half = ask(Q.integer(2*expr.exp), assumptions) + if half: + return ask(Q.negative(expr.base), assumptions) + return half + +@ImaginaryPredicate.register(log) # type:ignore +def _(expr, assumptions): + if ask(Q.real(expr.args[0]), assumptions): + if ask(Q.positive(expr.args[0]), assumptions): + return False + return + # XXX it should be enough to do + # return ask(Q.nonpositive(expr.args[0]), assumptions) + # but ask(Q.nonpositive(exp(x)), Q.imaginary(x)) -> None; + # it should return True since exp(x) will be either 0 or complex + if expr.args[0].func == exp or (expr.args[0].is_Pow and expr.args[0].base == E): + if expr.args[0].exp in [I, -I]: + return True + im = ask(Q.imaginary(expr.args[0]), assumptions) + if im is False: + return False + +@ImaginaryPredicate.register(exp) # type:ignore +def _(expr, assumptions): + a = expr.exp/I/pi + return ask(Q.integer(2*a) & ~Q.integer(a), assumptions) + +@ImaginaryPredicate.register_many(Number, NumberSymbol) # type:ignore +def _(expr, assumptions): + return not (expr.as_real_imag()[1] == 0) + +@ImaginaryPredicate.register(NaN) # type:ignore +def _(expr, assumptions): + return None + + +# AntihermitianPredicate + +@AntihermitianPredicate.register(object) # type:ignore +def _(expr, assumptions): + if isinstance(expr, MatrixBase): + return None + if ask(Q.zero(expr), assumptions): + return True + return ask(Q.imaginary(expr), assumptions) + +@AntihermitianPredicate.register(Add) # type:ignore +def _(expr, assumptions): + """ + * Antihermitian + Antihermitian -> Antihermitian + * Antihermitian + !Antihermitian -> !Antihermitian + """ + if expr.is_number: + raise MDNotImplementedError + return test_closed_group(expr, assumptions, Q.antihermitian) + +@AntihermitianPredicate.register(Mul) # type:ignore +def _(expr, assumptions): + """ + As long as there is at most only one noncommutative term: + + * Hermitian*Hermitian -> !Antihermitian + * Hermitian*Antihermitian -> Antihermitian + * Antihermitian*Antihermitian -> !Antihermitian + """ + if expr.is_number: + raise MDNotImplementedError + nccount = 0 + result = False + for arg in expr.args: + if ask(Q.antihermitian(arg), assumptions): + result = result ^ True + elif not ask(Q.hermitian(arg), assumptions): + break + if ask(~Q.commutative(arg), assumptions): + nccount += 1 + if nccount > 1: + break + else: + return result + +@AntihermitianPredicate.register(Pow) # type:ignore +def _(expr, assumptions): + """ + * Hermitian**Integer -> !Antihermitian + * Antihermitian**Even -> !Antihermitian + * Antihermitian**Odd -> Antihermitian + """ + if expr.is_number: + raise MDNotImplementedError + if ask(Q.hermitian(expr.base), assumptions): + if ask(Q.integer(expr.exp), assumptions): + return False + elif ask(Q.antihermitian(expr.base), assumptions): + if ask(Q.even(expr.exp), assumptions): + return False + elif ask(Q.odd(expr.exp), assumptions): + return True + raise MDNotImplementedError + +@AntihermitianPredicate.register(MatrixBase) # type:ignore +def _(mat, assumptions): + rows, cols = mat.shape + ret_val = True + for i in range(rows): + for j in range(i, cols): + cond = fuzzy_bool(Eq(mat[i, j], -conjugate(mat[j, i]))) + if cond is None: + ret_val = None + if cond == False: + return False + if ret_val is None: + raise MDNotImplementedError + return ret_val + + +# AlgebraicPredicate + +@AlgebraicPredicate.register_many(AlgebraicNumber, Float, GoldenRatio, # type:ignore + ImaginaryUnit, TribonacciConstant) +def _(expr, assumptions): + return True + +@AlgebraicPredicate.register_many(ComplexInfinity, Exp1, Infinity, # type:ignore + NegativeInfinity, Pi) +def _(expr, assumptions): + return False + +@AlgebraicPredicate.register_many(Add, Mul) # type:ignore +def _(expr, assumptions): + return test_closed_group(expr, assumptions, Q.algebraic) + +@AlgebraicPredicate.register(Pow) # type:ignore +def _(expr, assumptions): + if expr.base == E: + if ask(Q.algebraic(expr.exp), assumptions): + return ask(~Q.nonzero(expr.exp), assumptions) + return + return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions) + +@AlgebraicPredicate.register(Rational) # type:ignore +def _(expr, assumptions): + return expr.q != 0 + +@AlgebraicPredicate.register_many(asin, atan, cos, sin, tan) # type:ignore +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return ask(~Q.nonzero(x), assumptions) + +@AlgebraicPredicate.register(exp) # type:ignore +def _(expr, assumptions): + x = expr.exp + if ask(Q.algebraic(x), assumptions): + return ask(~Q.nonzero(x), assumptions) + +@AlgebraicPredicate.register_many(acot, cot) # type:ignore +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return False + +@AlgebraicPredicate.register_many(acos, log) # type:ignore +def _(expr, assumptions): + x = expr.args[0] + if ask(Q.algebraic(x), assumptions): + return ask(~Q.nonzero(x - 1), assumptions) diff --git a/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py b/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py new file mode 100644 index 0000000000000000000000000000000000000000..53afe3e5abe99109ec01a47f19f1a8a4c99c5628 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/lra_satask.py @@ -0,0 +1,286 @@ +from sympy.assumptions.assume import global_assumptions +from sympy.assumptions.cnf import CNF, EncodedCNF +from sympy.assumptions.ask import Q +from sympy.logic.inference import satisfiable +from sympy.logic.algorithms.lra_theory import UnhandledInput, ALLOWED_PRED +from sympy.matrices.kind import MatrixKind +from sympy.core.kind import NumberKind +from sympy.assumptions.assume import AppliedPredicate +from sympy.core.mul import Mul +from sympy.core.singleton import S + + +def lra_satask(proposition, assumptions=True, context=global_assumptions): + """ + Function to evaluate the proposition with assumptions using SAT algorithm + in conjunction with an Linear Real Arithmetic theory solver. + + Used to handle inequalities. Should eventually be depreciated and combined + into satask, but infinity handling and other things need to be implemented + before that can happen. + """ + props = CNF.from_prop(proposition) + _props = CNF.from_prop(~proposition) + + cnf = CNF.from_prop(assumptions) + assumptions = EncodedCNF() + assumptions.from_cnf(cnf) + + context_cnf = CNF() + if context: + context_cnf = context_cnf.extend(context) + + assumptions.add_from_cnf(context_cnf) + + return check_satisfiability(props, _props, assumptions) + +# Some predicates such as Q.prime can't be handled by lra_satask. +# For example, (x > 0) & (x < 1) & Q.prime(x) is unsat but lra_satask would think it was sat. +# WHITE_LIST is a list of predicates that can always be handled. +WHITE_LIST = ALLOWED_PRED | {Q.positive, Q.negative, Q.zero, Q.nonzero, Q.nonpositive, Q.nonnegative, + Q.extended_positive, Q.extended_negative, Q.extended_nonpositive, + Q.extended_negative, Q.extended_nonzero, Q.negative_infinite, + Q.positive_infinite} + + +def check_satisfiability(prop, _prop, factbase): + sat_true = factbase.copy() + sat_false = factbase.copy() + sat_true.add_from_cnf(prop) + sat_false.add_from_cnf(_prop) + + all_pred, all_exprs = get_all_pred_and_expr_from_enc_cnf(sat_true) + + for pred in all_pred: + if pred.function not in WHITE_LIST and pred.function != Q.ne: + raise UnhandledInput(f"LRASolver: {pred} is an unhandled predicate") + for expr in all_exprs: + if expr.kind == MatrixKind(NumberKind): + raise UnhandledInput(f"LRASolver: {expr} is of MatrixKind") + if expr == S.NaN: + raise UnhandledInput("LRASolver: nan") + + # convert old assumptions into predicates and add them to sat_true and sat_false + # also check for unhandled predicates + for assm in extract_pred_from_old_assum(all_exprs): + n = len(sat_true.encoding) + if assm not in sat_true.encoding: + sat_true.encoding[assm] = n+1 + sat_true.data.append([sat_true.encoding[assm]]) + + n = len(sat_false.encoding) + if assm not in sat_false.encoding: + sat_false.encoding[assm] = n+1 + sat_false.data.append([sat_false.encoding[assm]]) + + + sat_true = _preprocess(sat_true) + sat_false = _preprocess(sat_false) + + can_be_true = satisfiable(sat_true, use_lra_theory=True) is not False + can_be_false = satisfiable(sat_false, use_lra_theory=True) is not False + + if can_be_true and can_be_false: + return None + + if can_be_true and not can_be_false: + return True + + if not can_be_true and can_be_false: + return False + + if not can_be_true and not can_be_false: + raise ValueError("Inconsistent assumptions") + + +def _preprocess(enc_cnf): + """ + Returns an encoded cnf with only Q.eq, Q.gt, Q.lt, + Q.ge, and Q.le predicate. + + Converts every unequality into a disjunction of strict + inequalities. For example, x != 3 would become + x < 3 OR x > 3. + + Also converts all negated Q.ne predicates into + equalities. + """ + + # loops through each literal in each clause + # to construct a new, preprocessed encodedCNF + + enc_cnf = enc_cnf.copy() + cur_enc = 1 + rev_encoding = {value: key for key, value in enc_cnf.encoding.items()} + + new_encoding = {} + new_data = [] + for clause in enc_cnf.data: + new_clause = [] + for lit in clause: + if lit == 0: + new_clause.append(lit) + new_encoding[lit] = False + continue + prop = rev_encoding[abs(lit)] + negated = lit < 0 + sign = (lit > 0) - (lit < 0) + + prop = _pred_to_binrel(prop) + + if not isinstance(prop, AppliedPredicate): + if prop not in new_encoding: + new_encoding[prop] = cur_enc + cur_enc += 1 + lit = new_encoding[prop] + new_clause.append(sign*lit) + continue + + + if negated and prop.function == Q.eq: + negated = False + prop = Q.ne(*prop.arguments) + + if prop.function == Q.ne: + arg1, arg2 = prop.arguments + if negated: + new_prop = Q.eq(arg1, arg2) + if new_prop not in new_encoding: + new_encoding[new_prop] = cur_enc + cur_enc += 1 + + new_enc = new_encoding[new_prop] + new_clause.append(new_enc) + continue + else: + new_props = (Q.gt(arg1, arg2), Q.lt(arg1, arg2)) + for new_prop in new_props: + if new_prop not in new_encoding: + new_encoding[new_prop] = cur_enc + cur_enc += 1 + + new_enc = new_encoding[new_prop] + new_clause.append(new_enc) + continue + + if prop.function == Q.eq and negated: + assert False + + if prop not in new_encoding: + new_encoding[prop] = cur_enc + cur_enc += 1 + new_clause.append(new_encoding[prop]*sign) + new_data.append(new_clause) + + assert len(new_encoding) >= cur_enc - 1 + + enc_cnf = EncodedCNF(new_data, new_encoding) + return enc_cnf + + +def _pred_to_binrel(pred): + if not isinstance(pred, AppliedPredicate): + return pred + + if pred.function in pred_to_pos_neg_zero: + f = pred_to_pos_neg_zero[pred.function] + if f is False: + return False + pred = f(pred.arguments[0]) + + if pred.function == Q.positive: + pred = Q.gt(pred.arguments[0], 0) + elif pred.function == Q.negative: + pred = Q.lt(pred.arguments[0], 0) + elif pred.function == Q.zero: + pred = Q.eq(pred.arguments[0], 0) + elif pred.function == Q.nonpositive: + pred = Q.le(pred.arguments[0], 0) + elif pred.function == Q.nonnegative: + pred = Q.ge(pred.arguments[0], 0) + elif pred.function == Q.nonzero: + pred = Q.ne(pred.arguments[0], 0) + + return pred + +pred_to_pos_neg_zero = { + Q.extended_positive: Q.positive, + Q.extended_negative: Q.negative, + Q.extended_nonpositive: Q.nonpositive, + Q.extended_negative: Q.negative, + Q.extended_nonzero: Q.nonzero, + Q.negative_infinite: False, + Q.positive_infinite: False +} + +def get_all_pred_and_expr_from_enc_cnf(enc_cnf): + all_exprs = set() + all_pred = set() + for pred in enc_cnf.encoding.keys(): + if isinstance(pred, AppliedPredicate): + all_pred.add(pred) + all_exprs.update(pred.arguments) + + return all_pred, all_exprs + +def extract_pred_from_old_assum(all_exprs): + """ + Returns a list of relevant new assumption predicate + based on any old assumptions. + + Raises an UnhandledInput exception if any of the assumptions are + unhandled. + + Ignored predicate: + - commutative + - complex + - algebraic + - transcendental + - extended_real + - real + - all matrix predicate + - rational + - irrational + + Example + ======= + >>> from sympy.assumptions.lra_satask import extract_pred_from_old_assum + >>> from sympy import symbols + >>> x, y = symbols("x y", positive=True) + >>> extract_pred_from_old_assum([x, y, 2]) + [Q.positive(x), Q.positive(y)] + """ + ret = [] + for expr in all_exprs: + if not hasattr(expr, "free_symbols"): + continue + if len(expr.free_symbols) == 0: + continue + + if expr.is_real is not True: + raise UnhandledInput(f"LRASolver: {expr} must be real") + # test for I times imaginary variable; such expressions are considered real + if isinstance(expr, Mul) and any(arg.is_real is not True for arg in expr.args): + raise UnhandledInput(f"LRASolver: {expr} must be real") + + if expr.is_integer == True and expr.is_zero != True: + raise UnhandledInput(f"LRASolver: {expr} is an integer") + if expr.is_integer == False: + raise UnhandledInput(f"LRASolver: {expr} can't be an integer") + if expr.is_rational == False: + raise UnhandledInput(f"LRASolver: {expr} is irational") + + if expr.is_zero: + ret.append(Q.zero(expr)) + elif expr.is_positive: + ret.append(Q.positive(expr)) + elif expr.is_negative: + ret.append(Q.negative(expr)) + elif expr.is_nonzero: + ret.append(Q.nonzero(expr)) + elif expr.is_nonpositive: + ret.append(Q.nonpositive(expr)) + elif expr.is_nonnegative: + ret.append(Q.nonnegative(expr)) + + return ret diff --git a/lib/python3.12/site-packages/sympy/assumptions/refine.py b/lib/python3.12/site-packages/sympy/assumptions/refine.py new file mode 100644 index 0000000000000000000000000000000000000000..8d5d0f6028fda7a15c0ac66bd7001779fa2fc068 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/refine.py @@ -0,0 +1,405 @@ +from __future__ import annotations +from typing import Callable + +from sympy.core import S, Add, Expr, Basic, Mul, Pow, Rational +from sympy.core.logic import fuzzy_not +from sympy.logic.boolalg import Boolean + +from sympy.assumptions import ask, Q # type: ignore + + +def refine(expr, assumptions=True): + """ + Simplify an expression using assumptions. + + Explanation + =========== + + Unlike :func:`~.simplify()` which performs structural simplification + without any assumption, this function transforms the expression into + the form which is only valid under certain assumptions. Note that + ``simplify()`` is generally not done in refining process. + + Refining boolean expression involves reducing it to ``S.true`` or + ``S.false``. Unlike :func:`~.ask()`, the expression will not be reduced + if the truth value cannot be determined. + + Examples + ======== + + >>> from sympy import refine, sqrt, Q + >>> from sympy.abc import x + >>> refine(sqrt(x**2), Q.real(x)) + Abs(x) + >>> refine(sqrt(x**2), Q.positive(x)) + x + + >>> refine(Q.real(x), Q.positive(x)) + True + >>> refine(Q.positive(x), Q.real(x)) + Q.positive(x) + + See Also + ======== + + sympy.simplify.simplify.simplify : Structural simplification without assumptions. + sympy.assumptions.ask.ask : Query for boolean expressions using assumptions. + """ + if not isinstance(expr, Basic): + return expr + + if not expr.is_Atom: + args = [refine(arg, assumptions) for arg in expr.args] + # TODO: this will probably not work with Integral or Polynomial + expr = expr.func(*args) + if hasattr(expr, '_eval_refine'): + ref_expr = expr._eval_refine(assumptions) + if ref_expr is not None: + return ref_expr + name = expr.__class__.__name__ + handler = handlers_dict.get(name, None) + if handler is None: + return expr + new_expr = handler(expr, assumptions) + if (new_expr is None) or (expr == new_expr): + return expr + if not isinstance(new_expr, Expr): + return new_expr + return refine(new_expr, assumptions) + + +def refine_abs(expr, assumptions): + """ + Handler for the absolute value. + + Examples + ======== + + >>> from sympy import Q, Abs + >>> from sympy.assumptions.refine import refine_abs + >>> from sympy.abc import x + >>> refine_abs(Abs(x), Q.real(x)) + >>> refine_abs(Abs(x), Q.positive(x)) + x + >>> refine_abs(Abs(x), Q.negative(x)) + -x + + """ + from sympy.functions.elementary.complexes import Abs + arg = expr.args[0] + if ask(Q.real(arg), assumptions) and \ + fuzzy_not(ask(Q.negative(arg), assumptions)): + # if it's nonnegative + return arg + if ask(Q.negative(arg), assumptions): + return -arg + # arg is Mul + if isinstance(arg, Mul): + r = [refine(abs(a), assumptions) for a in arg.args] + non_abs = [] + in_abs = [] + for i in r: + if isinstance(i, Abs): + in_abs.append(i.args[0]) + else: + non_abs.append(i) + return Mul(*non_abs) * Abs(Mul(*in_abs)) + + +def refine_Pow(expr, assumptions): + """ + Handler for instances of Pow. + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.refine import refine_Pow + >>> from sympy.abc import x,y,z + >>> refine_Pow((-1)**x, Q.real(x)) + >>> refine_Pow((-1)**x, Q.even(x)) + 1 + >>> refine_Pow((-1)**x, Q.odd(x)) + -1 + + For powers of -1, even parts of the exponent can be simplified: + + >>> refine_Pow((-1)**(x+y), Q.even(x)) + (-1)**y + >>> refine_Pow((-1)**(x+y+z), Q.odd(x) & Q.odd(z)) + (-1)**y + >>> refine_Pow((-1)**(x+y+2), Q.odd(x)) + (-1)**(y + 1) + >>> refine_Pow((-1)**(x+3), True) + (-1)**(x + 1) + + """ + from sympy.functions.elementary.complexes import Abs + from sympy.functions import sign + if isinstance(expr.base, Abs): + if ask(Q.real(expr.base.args[0]), assumptions) and \ + ask(Q.even(expr.exp), assumptions): + return expr.base.args[0] ** expr.exp + if ask(Q.real(expr.base), assumptions): + if expr.base.is_number: + if ask(Q.even(expr.exp), assumptions): + return abs(expr.base) ** expr.exp + if ask(Q.odd(expr.exp), assumptions): + return sign(expr.base) * abs(expr.base) ** expr.exp + if isinstance(expr.exp, Rational): + if isinstance(expr.base, Pow): + return abs(expr.base.base) ** (expr.base.exp * expr.exp) + + if expr.base is S.NegativeOne: + if expr.exp.is_Add: + + old = expr + + # For powers of (-1) we can remove + # - even terms + # - pairs of odd terms + # - a single odd term + 1 + # - A numerical constant N can be replaced with mod(N,2) + + coeff, terms = expr.exp.as_coeff_add() + terms = set(terms) + even_terms = set() + odd_terms = set() + initial_number_of_terms = len(terms) + + for t in terms: + if ask(Q.even(t), assumptions): + even_terms.add(t) + elif ask(Q.odd(t), assumptions): + odd_terms.add(t) + + terms -= even_terms + if len(odd_terms) % 2: + terms -= odd_terms + new_coeff = (coeff + S.One) % 2 + else: + terms -= odd_terms + new_coeff = coeff % 2 + + if new_coeff != coeff or len(terms) < initial_number_of_terms: + terms.add(new_coeff) + expr = expr.base**(Add(*terms)) + + # Handle (-1)**((-1)**n/2 + m/2) + e2 = 2*expr.exp + if ask(Q.even(e2), assumptions): + if e2.could_extract_minus_sign(): + e2 *= expr.base + if e2.is_Add: + i, p = e2.as_two_terms() + if p.is_Pow and p.base is S.NegativeOne: + if ask(Q.integer(p.exp), assumptions): + i = (i + 1)/2 + if ask(Q.even(i), assumptions): + return expr.base**p.exp + elif ask(Q.odd(i), assumptions): + return expr.base**(p.exp + 1) + else: + return expr.base**(p.exp + i) + + if old != expr: + return expr + + +def refine_atan2(expr, assumptions): + """ + Handler for the atan2 function. + + Examples + ======== + + >>> from sympy import Q, atan2 + >>> from sympy.assumptions.refine import refine_atan2 + >>> from sympy.abc import x, y + >>> refine_atan2(atan2(y,x), Q.real(y) & Q.positive(x)) + atan(y/x) + >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.negative(x)) + atan(y/x) - pi + >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.negative(x)) + atan(y/x) + pi + >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.negative(x)) + pi + >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.zero(x)) + pi/2 + >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.zero(x)) + -pi/2 + >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.zero(x)) + nan + """ + from sympy.functions.elementary.trigonometric import atan + y, x = expr.args + if ask(Q.real(y) & Q.positive(x), assumptions): + return atan(y / x) + elif ask(Q.negative(y) & Q.negative(x), assumptions): + return atan(y / x) - S.Pi + elif ask(Q.positive(y) & Q.negative(x), assumptions): + return atan(y / x) + S.Pi + elif ask(Q.zero(y) & Q.negative(x), assumptions): + return S.Pi + elif ask(Q.positive(y) & Q.zero(x), assumptions): + return S.Pi/2 + elif ask(Q.negative(y) & Q.zero(x), assumptions): + return -S.Pi/2 + elif ask(Q.zero(y) & Q.zero(x), assumptions): + return S.NaN + else: + return expr + + +def refine_re(expr, assumptions): + """ + Handler for real part. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_re + >>> from sympy import Q, re + >>> from sympy.abc import x + >>> refine_re(re(x), Q.real(x)) + x + >>> refine_re(re(x), Q.imaginary(x)) + 0 + """ + arg = expr.args[0] + if ask(Q.real(arg), assumptions): + return arg + if ask(Q.imaginary(arg), assumptions): + return S.Zero + return _refine_reim(expr, assumptions) + + +def refine_im(expr, assumptions): + """ + Handler for imaginary part. + + Explanation + =========== + + >>> from sympy.assumptions.refine import refine_im + >>> from sympy import Q, im + >>> from sympy.abc import x + >>> refine_im(im(x), Q.real(x)) + 0 + >>> refine_im(im(x), Q.imaginary(x)) + -I*x + """ + arg = expr.args[0] + if ask(Q.real(arg), assumptions): + return S.Zero + if ask(Q.imaginary(arg), assumptions): + return - S.ImaginaryUnit * arg + return _refine_reim(expr, assumptions) + +def refine_arg(expr, assumptions): + """ + Handler for complex argument + + Explanation + =========== + + >>> from sympy.assumptions.refine import refine_arg + >>> from sympy import Q, arg + >>> from sympy.abc import x + >>> refine_arg(arg(x), Q.positive(x)) + 0 + >>> refine_arg(arg(x), Q.negative(x)) + pi + """ + rg = expr.args[0] + if ask(Q.positive(rg), assumptions): + return S.Zero + if ask(Q.negative(rg), assumptions): + return S.Pi + return None + + +def _refine_reim(expr, assumptions): + # Helper function for refine_re & refine_im + expanded = expr.expand(complex = True) + if expanded != expr: + refined = refine(expanded, assumptions) + if refined != expanded: + return refined + # Best to leave the expression as is + return None + + +def refine_sign(expr, assumptions): + """ + Handler for sign. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_sign + >>> from sympy import Symbol, Q, sign, im + >>> x = Symbol('x', real = True) + >>> expr = sign(x) + >>> refine_sign(expr, Q.positive(x) & Q.nonzero(x)) + 1 + >>> refine_sign(expr, Q.negative(x) & Q.nonzero(x)) + -1 + >>> refine_sign(expr, Q.zero(x)) + 0 + >>> y = Symbol('y', imaginary = True) + >>> expr = sign(y) + >>> refine_sign(expr, Q.positive(im(y))) + I + >>> refine_sign(expr, Q.negative(im(y))) + -I + """ + arg = expr.args[0] + if ask(Q.zero(arg), assumptions): + return S.Zero + if ask(Q.real(arg)): + if ask(Q.positive(arg), assumptions): + return S.One + if ask(Q.negative(arg), assumptions): + return S.NegativeOne + if ask(Q.imaginary(arg)): + arg_re, arg_im = arg.as_real_imag() + if ask(Q.positive(arg_im), assumptions): + return S.ImaginaryUnit + if ask(Q.negative(arg_im), assumptions): + return -S.ImaginaryUnit + return expr + + +def refine_matrixelement(expr, assumptions): + """ + Handler for symmetric part. + + Examples + ======== + + >>> from sympy.assumptions.refine import refine_matrixelement + >>> from sympy import MatrixSymbol, Q + >>> X = MatrixSymbol('X', 3, 3) + >>> refine_matrixelement(X[0, 1], Q.symmetric(X)) + X[0, 1] + >>> refine_matrixelement(X[1, 0], Q.symmetric(X)) + X[0, 1] + """ + from sympy.matrices.expressions.matexpr import MatrixElement + matrix, i, j = expr.args + if ask(Q.symmetric(matrix), assumptions): + if (i - j).could_extract_minus_sign(): + return expr + return MatrixElement(matrix, j, i) + +handlers_dict: dict[str, Callable[[Expr, Boolean], Expr]] = { + 'Abs': refine_abs, + 'Pow': refine_Pow, + 'atan2': refine_atan2, + 're': refine_re, + 'im': refine_im, + 'arg': refine_arg, + 'sign': refine_sign, + 'MatrixElement': refine_matrixelement +} diff --git a/lib/python3.12/site-packages/sympy/assumptions/satask.py b/lib/python3.12/site-packages/sympy/assumptions/satask.py new file mode 100644 index 0000000000000000000000000000000000000000..ffc13f6d3bc3fb7f573c8d5d0564b780440c1a8c --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/satask.py @@ -0,0 +1,369 @@ +""" +Module to evaluate the proposition with assumptions using SAT algorithm. +""" + +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.kind import NumberKind, UndefinedKind +from sympy.assumptions.ask_generated import get_all_known_matrix_facts, get_all_known_number_facts +from sympy.assumptions.assume import global_assumptions, AppliedPredicate +from sympy.assumptions.sathandlers import class_fact_registry +from sympy.core import oo +from sympy.logic.inference import satisfiable +from sympy.assumptions.cnf import CNF, EncodedCNF +from sympy.matrices.kind import MatrixKind + + +def satask(proposition, assumptions=True, context=global_assumptions, + use_known_facts=True, iterations=oo): + """ + Function to evaluate the proposition with assumptions using SAT algorithm. + + This function extracts every fact relevant to the expressions composing + proposition and assumptions. For example, if a predicate containing + ``Abs(x)`` is proposed, then ``Q.zero(Abs(x)) | Q.positive(Abs(x))`` + will be found and passed to SAT solver because ``Q.nonnegative`` is + registered as a fact for ``Abs``. + + Proposition is evaluated to ``True`` or ``False`` if the truth value can be + determined. If not, ``None`` is returned. + + Parameters + ========== + + proposition : Any boolean expression. + Proposition which will be evaluated to boolean value. + + assumptions : Any boolean expression, optional. + Local assumptions to evaluate the *proposition*. + + context : AssumptionsContext, optional. + Default assumptions to evaluate the *proposition*. By default, + this is ``sympy.assumptions.global_assumptions`` variable. + + use_known_facts : bool, optional. + If ``True``, facts from ``sympy.assumptions.ask_generated`` + module are passed to SAT solver as well. + + iterations : int, optional. + Number of times that relevant facts are recursively extracted. + Default is infinite times until no new fact is found. + + Returns + ======= + + ``True``, ``False``, or ``None`` + + Examples + ======== + + >>> from sympy import Abs, Q + >>> from sympy.assumptions.satask import satask + >>> from sympy.abc import x + >>> satask(Q.zero(Abs(x)), Q.zero(x)) + True + + """ + props = CNF.from_prop(proposition) + _props = CNF.from_prop(~proposition) + + assumptions = CNF.from_prop(assumptions) + + context_cnf = CNF() + if context: + context_cnf = context_cnf.extend(context) + + sat = get_all_relevant_facts(props, assumptions, context_cnf, + use_known_facts=use_known_facts, iterations=iterations) + sat.add_from_cnf(assumptions) + if context: + sat.add_from_cnf(context_cnf) + + return check_satisfiability(props, _props, sat) + + +def check_satisfiability(prop, _prop, factbase): + sat_true = factbase.copy() + sat_false = factbase.copy() + sat_true.add_from_cnf(prop) + sat_false.add_from_cnf(_prop) + can_be_true = satisfiable(sat_true) + can_be_false = satisfiable(sat_false) + + if can_be_true and can_be_false: + return None + + if can_be_true and not can_be_false: + return True + + if not can_be_true and can_be_false: + return False + + if not can_be_true and not can_be_false: + # TODO: Run additional checks to see which combination of the + # assumptions, global_assumptions, and relevant_facts are + # inconsistent. + raise ValueError("Inconsistent assumptions") + + +def extract_predargs(proposition, assumptions=None, context=None): + """ + Extract every expression in the argument of predicates from *proposition*, + *assumptions* and *context*. + + Parameters + ========== + + proposition : sympy.assumptions.cnf.CNF + + assumptions : sympy.assumptions.cnf.CNF, optional. + + context : sympy.assumptions.cnf.CNF, optional. + CNF generated from assumptions context. + + Examples + ======== + + >>> from sympy import Q, Abs + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.satask import extract_predargs + >>> from sympy.abc import x, y + >>> props = CNF.from_prop(Q.zero(Abs(x*y))) + >>> assump = CNF.from_prop(Q.zero(x) & Q.zero(y)) + >>> extract_predargs(props, assump) + {x, y, Abs(x*y)} + + """ + req_keys = find_symbols(proposition) + keys = proposition.all_predicates() + # XXX: We need this since True/False are not Basic + lkeys = set() + if assumptions: + lkeys |= assumptions.all_predicates() + if context: + lkeys |= context.all_predicates() + + lkeys = lkeys - {S.true, S.false} + tmp_keys = None + while tmp_keys != set(): + tmp = set() + for l in lkeys: + syms = find_symbols(l) + if (syms & req_keys) != set(): + tmp |= syms + tmp_keys = tmp - req_keys + req_keys |= tmp_keys + keys |= {l for l in lkeys if find_symbols(l) & req_keys != set()} + + exprs = set() + for key in keys: + if isinstance(key, AppliedPredicate): + exprs |= set(key.arguments) + else: + exprs.add(key) + return exprs + +def find_symbols(pred): + """ + Find every :obj:`~.Symbol` in *pred*. + + Parameters + ========== + + pred : sympy.assumptions.cnf.CNF, or any Expr. + + """ + if isinstance(pred, CNF): + symbols = set() + for a in pred.all_predicates(): + symbols |= find_symbols(a) + return symbols + return pred.atoms(Symbol) + + +def get_relevant_clsfacts(exprs, relevant_facts=None): + """ + Extract relevant facts from the items in *exprs*. Facts are defined in + ``assumptions.sathandlers`` module. + + This function is recursively called by ``get_all_relevant_facts()``. + + Parameters + ========== + + exprs : set + Expressions whose relevant facts are searched. + + relevant_facts : sympy.assumptions.cnf.CNF, optional. + Pre-discovered relevant facts. + + Returns + ======= + + exprs : set + Candidates for next relevant fact searching. + + relevant_facts : sympy.assumptions.cnf.CNF + Updated relevant facts. + + Examples + ======== + + Here, we will see how facts relevant to ``Abs(x*y)`` are recursively + extracted. On the first run, set containing the expression is passed + without pre-discovered relevant facts. The result is a set containing + candidates for next run, and ``CNF()`` instance containing facts + which are relevant to ``Abs`` and its argument. + + >>> from sympy import Abs + >>> from sympy.assumptions.satask import get_relevant_clsfacts + >>> from sympy.abc import x, y + >>> exprs = {Abs(x*y)} + >>> exprs, facts = get_relevant_clsfacts(exprs) + >>> exprs + {x*y} + >>> facts.clauses #doctest: +SKIP + {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)})} + + We pass the first run's results to the second run, and get the expressions + for next run and updated facts. + + >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) + >>> exprs + {x, y} + + On final run, no more candidate is returned thus we know that all + relevant facts are successfully retrieved. + + >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) + >>> exprs + set() + + """ + if not relevant_facts: + relevant_facts = CNF() + + newexprs = set() + for expr in exprs: + for fact in class_fact_registry(expr): + newfact = CNF.to_CNF(fact) + relevant_facts = relevant_facts._and(newfact) + for key in newfact.all_predicates(): + if isinstance(key, AppliedPredicate): + newexprs |= set(key.arguments) + + return newexprs - exprs, relevant_facts + + +def get_all_relevant_facts(proposition, assumptions, context, + use_known_facts=True, iterations=oo): + """ + Extract all relevant facts from *proposition* and *assumptions*. + + This function extracts the facts by recursively calling + ``get_relevant_clsfacts()``. Extracted facts are converted to + ``EncodedCNF`` and returned. + + Parameters + ========== + + proposition : sympy.assumptions.cnf.CNF + CNF generated from proposition expression. + + assumptions : sympy.assumptions.cnf.CNF + CNF generated from assumption expression. + + context : sympy.assumptions.cnf.CNF + CNF generated from assumptions context. + + use_known_facts : bool, optional. + If ``True``, facts from ``sympy.assumptions.ask_generated`` + module are encoded as well. + + iterations : int, optional. + Number of times that relevant facts are recursively extracted. + Default is infinite times until no new fact is found. + + Returns + ======= + + sympy.assumptions.cnf.EncodedCNF + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.cnf import CNF + >>> from sympy.assumptions.satask import get_all_relevant_facts + >>> from sympy.abc import x, y + >>> props = CNF.from_prop(Q.nonzero(x*y)) + >>> assump = CNF.from_prop(Q.nonzero(x)) + >>> context = CNF.from_prop(Q.nonzero(y)) + >>> get_all_relevant_facts(props, assump, context) #doctest: +SKIP + + + """ + # The relevant facts might introduce new keys, e.g., Q.zero(x*y) will + # introduce the keys Q.zero(x) and Q.zero(y), so we need to run it until + # we stop getting new things. Hopefully this strategy won't lead to an + # infinite loop in the future. + i = 0 + relevant_facts = CNF() + all_exprs = set() + while True: + if i == 0: + exprs = extract_predargs(proposition, assumptions, context) + all_exprs |= exprs + exprs, relevant_facts = get_relevant_clsfacts(exprs, relevant_facts) + i += 1 + if i >= iterations: + break + if not exprs: + break + + if use_known_facts: + known_facts_CNF = CNF() + + if any(expr.kind == MatrixKind(NumberKind) for expr in all_exprs): + known_facts_CNF.add_clauses(get_all_known_matrix_facts()) + # check for undefinedKind since kind system isn't fully implemented + if any(((expr.kind == NumberKind) or (expr.kind == UndefinedKind)) for expr in all_exprs): + known_facts_CNF.add_clauses(get_all_known_number_facts()) + + kf_encoded = EncodedCNF() + kf_encoded.from_cnf(known_facts_CNF) + + def translate_literal(lit, delta): + if lit > 0: + return lit + delta + else: + return lit - delta + + def translate_data(data, delta): + return [{translate_literal(i, delta) for i in clause} for clause in data] + data = [] + symbols = [] + n_lit = len(kf_encoded.symbols) + for i, expr in enumerate(all_exprs): + symbols += [pred(expr) for pred in kf_encoded.symbols] + data += translate_data(kf_encoded.data, i * n_lit) + + encoding = dict(list(zip(symbols, range(1, len(symbols)+1)))) + ctx = EncodedCNF(data, encoding) + else: + ctx = EncodedCNF() + + ctx.add_from_cnf(relevant_facts) + + return ctx diff --git a/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py b/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py new file mode 100644 index 0000000000000000000000000000000000000000..a11199eb0e547187ab280c18196c0259c178e004 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/sathandlers.py @@ -0,0 +1,322 @@ +from collections import defaultdict + +from sympy.assumptions.ask import Q +from sympy.core import (Add, Mul, Pow, Number, NumberSymbol, Symbol) +from sympy.core.numbers import ImaginaryUnit +from sympy.functions.elementary.complexes import Abs +from sympy.logic.boolalg import (Equivalent, And, Or, Implies) +from sympy.matrices.expressions import MatMul + +# APIs here may be subject to change + + +### Helper functions ### + +def allargs(symbol, fact, expr): + """ + Apply all arguments of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import allargs + >>> from sympy.abc import x, y + >>> allargs(x, Q.negative(x) | Q.positive(x), x*y) + (Q.negative(x) | Q.positive(x)) & (Q.negative(y) | Q.positive(y)) + + """ + return And(*[fact.subs(symbol, arg) for arg in expr.args]) + + +def anyarg(symbol, fact, expr): + """ + Apply any argument of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import anyarg + >>> from sympy.abc import x, y + >>> anyarg(x, Q.negative(x) & Q.positive(x), x*y) + (Q.negative(x) & Q.positive(x)) | (Q.negative(y) & Q.positive(y)) + + """ + return Or(*[fact.subs(symbol, arg) for arg in expr.args]) + + +def exactlyonearg(symbol, fact, expr): + """ + Apply exactly one argument of the expression to the fact structure. + + Parameters + ========== + + symbol : Symbol + A placeholder symbol. + + fact : Boolean + Resulting ``Boolean`` expression. + + expr : Expr + + Examples + ======== + + >>> from sympy import Q + >>> from sympy.assumptions.sathandlers import exactlyonearg + >>> from sympy.abc import x, y + >>> exactlyonearg(x, Q.positive(x), x*y) + (Q.positive(x) & ~Q.positive(y)) | (Q.positive(y) & ~Q.positive(x)) + + """ + pred_args = [fact.subs(symbol, arg) for arg in expr.args] + res = Or(*[And(pred_args[i], *[~lit for lit in pred_args[:i] + + pred_args[i+1:]]) for i in range(len(pred_args))]) + return res + + +### Fact registry ### + +class ClassFactRegistry: + """ + Register handlers against classes. + + Explanation + =========== + + ``register`` method registers the handler function for a class. Here, + handler function should return a single fact. ``multiregister`` method + registers the handler function for multiple classes. Here, handler function + should return a container of multiple facts. + + ``registry(expr)`` returns a set of facts for *expr*. + + Examples + ======== + + Here, we register the facts for ``Abs``. + + >>> from sympy import Abs, Equivalent, Q + >>> from sympy.assumptions.sathandlers import ClassFactRegistry + >>> reg = ClassFactRegistry() + >>> @reg.register(Abs) + ... def f1(expr): + ... return Q.nonnegative(expr) + >>> @reg.register(Abs) + ... def f2(expr): + ... arg = expr.args[0] + ... return Equivalent(~Q.zero(arg), ~Q.zero(expr)) + + Calling the registry with expression returns the defined facts for the + expression. + + >>> from sympy.abc import x + >>> reg(Abs(x)) + {Q.nonnegative(Abs(x)), Equivalent(~Q.zero(x), ~Q.zero(Abs(x)))} + + Multiple facts can be registered at once by ``multiregister`` method. + + >>> reg2 = ClassFactRegistry() + >>> @reg2.multiregister(Abs) + ... def _(expr): + ... arg = expr.args[0] + ... return [Q.even(arg) >> Q.even(expr), Q.odd(arg) >> Q.odd(expr)] + >>> reg2(Abs(x)) + {Implies(Q.even(x), Q.even(Abs(x))), Implies(Q.odd(x), Q.odd(Abs(x)))} + + """ + def __init__(self): + self.singlefacts = defaultdict(frozenset) + self.multifacts = defaultdict(frozenset) + + def register(self, cls): + def _(func): + self.singlefacts[cls] |= {func} + return func + return _ + + def multiregister(self, *classes): + def _(func): + for cls in classes: + self.multifacts[cls] |= {func} + return func + return _ + + def __getitem__(self, key): + ret1 = self.singlefacts[key] + for k in self.singlefacts: + if issubclass(key, k): + ret1 |= self.singlefacts[k] + + ret2 = self.multifacts[key] + for k in self.multifacts: + if issubclass(key, k): + ret2 |= self.multifacts[k] + + return ret1, ret2 + + def __call__(self, expr): + ret = set() + + handlers1, handlers2 = self[type(expr)] + + ret.update(h(expr) for h in handlers1) + for h in handlers2: + ret.update(h(expr)) + return ret + +class_fact_registry = ClassFactRegistry() + + + +### Class fact registration ### + +x = Symbol('x') + +## Abs ## + +@class_fact_registry.multiregister(Abs) +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), + ] + + +### Add ## + +@class_fact_registry.multiregister(Add) +def _(expr): + return [allargs(x, Q.positive(x), expr) >> Q.positive(expr), + allargs(x, Q.negative(x), expr) >> Q.negative(expr), + allargs(x, Q.real(x), expr) >> Q.real(expr), + allargs(x, Q.rational(x), expr) >> Q.rational(expr), + allargs(x, Q.integer(x), expr) >> Q.integer(expr), + exactlyonearg(x, ~Q.integer(x), expr) >> ~Q.integer(expr), + ] + +@class_fact_registry.register(Add) +def _(expr): + allargs_real = allargs(x, Q.real(x), expr) + onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) + return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) + + +### Mul ### + +@class_fact_registry.multiregister(Mul) +def _(expr): + return [Equivalent(Q.zero(expr), anyarg(x, Q.zero(x), expr)), + allargs(x, Q.positive(x), expr) >> Q.positive(expr), + allargs(x, Q.real(x), expr) >> Q.real(expr), + allargs(x, Q.rational(x), expr) >> Q.rational(expr), + allargs(x, Q.integer(x), expr) >> Q.integer(expr), + exactlyonearg(x, ~Q.rational(x), expr) >> ~Q.integer(expr), + allargs(x, Q.commutative(x), expr) >> Q.commutative(expr), + ] + +@class_fact_registry.register(Mul) +def _(expr): + # Implicitly assumes Mul has more than one arg + # Would be allargs(x, Q.prime(x) | Q.composite(x)) except 1 is composite + # More advanced prime assumptions will require inequalities, as 1 provides + # a corner case. + allargs_prime = allargs(x, Q.prime(x), expr) + return Implies(allargs_prime, ~Q.prime(expr)) + +@class_fact_registry.register(Mul) +def _(expr): + # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) + allargs_imag_or_real = allargs(x, Q.imaginary(x) | Q.real(x), expr) + onearg_imaginary = exactlyonearg(x, Q.imaginary(x), expr) + return Implies(allargs_imag_or_real, Implies(onearg_imaginary, Q.imaginary(expr))) + +@class_fact_registry.register(Mul) +def _(expr): + allargs_real = allargs(x, Q.real(x), expr) + onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) + return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) + +@class_fact_registry.register(Mul) +def _(expr): + # Including the integer qualification means we don't need to add any facts + # for odd, since the assumptions already know that every integer is + # exactly one of even or odd. + allargs_integer = allargs(x, Q.integer(x), expr) + anyarg_even = anyarg(x, Q.even(x), expr) + return Implies(allargs_integer, Equivalent(anyarg_even, Q.even(expr))) + + +### MatMul ### + +@class_fact_registry.register(MatMul) +def _(expr): + allargs_square = allargs(x, Q.square(x), expr) + allargs_invertible = allargs(x, Q.invertible(x), expr) + return Implies(allargs_square, Equivalent(Q.invertible(expr), allargs_invertible)) + + +### Pow ### + +@class_fact_registry.multiregister(Pow) +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)) + ] + + +### Numbers ### + +_old_assump_getters = { + Q.positive: lambda o: o.is_positive, + Q.zero: lambda o: o.is_zero, + Q.negative: lambda o: o.is_negative, + Q.rational: lambda o: o.is_rational, + Q.irrational: lambda o: o.is_irrational, + Q.even: lambda o: o.is_even, + Q.odd: lambda o: o.is_odd, + Q.imaginary: lambda o: o.is_imaginary, + Q.prime: lambda o: o.is_prime, + Q.composite: lambda o: o.is_composite, +} + +@class_fact_registry.multiregister(Number, NumberSymbol, ImaginaryUnit) +def _(expr): + ret = [] + for p, getter in _old_assump_getters.items(): + pred = p(expr) + prop = getter(expr) + if prop is not None: + ret.append(Equivalent(pred, prop)) + return ret diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__init__.py b/lib/python3.12/site-packages/sympy/assumptions/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21f976dbf2ce57840881288ddd3df10ea014c287 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_assumptions_2.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_assumptions_2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8df80a24a54ad4de66ebabe9c6b75a3d4b183ae Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_assumptions_2.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_context.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_context.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0888f5067e709d63a74984efcc805e19207b868c Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_context.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_matrices.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_matrices.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5ef86e3d8f2963328dcaf81f694f35ac245e3c7 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_matrices.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_refine.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_refine.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4d31ca1e1f4769ef3c99d2adc7b0d6a9b7f78c8 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_refine.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_rel_queries.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_rel_queries.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac779cf5397c081061cf84bbaa8c9407d3e08f0b Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_rel_queries.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_satask.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_satask.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebf5ff65207cc3c8651eeae0239312621f9400e0 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_satask.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_sathandlers.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_sathandlers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e75dcd90b2869182e2ad058b2dcc5f4ef702e0f4 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_sathandlers.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_wrapper.cpython-312.pyc b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_wrapper.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..753676e1f3c0910bd55b5d6e336c39025a97f0da Binary files /dev/null and b/lib/python3.12/site-packages/sympy/assumptions/tests/__pycache__/test_wrapper.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_assumptions_2.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_assumptions_2.py new file mode 100644 index 0000000000000000000000000000000000000000..493fe4a7ed70301754ad2cfe181c5acf30433768 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_assumptions_2.py @@ -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 diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_context.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_context.py new file mode 100644 index 0000000000000000000000000000000000000000..be162f1c69492218ff90ea69492925d7779567a4 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_context.py @@ -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 diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_matrices.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..8bfa990f080eebe4d6dd5bfdd733ce1a19adf329 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_matrices.py @@ -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)) diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_query.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_query.py new file mode 100644 index 0000000000000000000000000000000000000000..797a6dcc4dba46c0292508adcbb47316dc197e9d --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_query.py @@ -0,0 +1,2417 @@ +from sympy.abc import t, w, x, y, z, n, k, m, p, i +from sympy.assumptions import (ask, AssumptionsContext, Q, register_handler, + remove_handler) +from sympy.assumptions.assume import assuming, global_assumptions, Predicate +from sympy.assumptions.cnf import CNF, Literal +from sympy.assumptions.facts import (single_fact_lookup, + get_known_facts, generate_known_facts_dict, get_known_facts_keys) +from sympy.assumptions.handlers import AskHandler +from sympy.assumptions.ask_generated import (get_all_known_facts, + get_known_facts_dict) +from sympy.core.add import Add +from sympy.core.numbers import (I, Integer, Rational, oo, zoo, pi) +from sympy.core.singleton import S +from sympy.core.power import Pow +from sympy.core.symbol import Str, symbols, Symbol +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import (Abs, im, re, sign) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import ( + acos, acot, asin, atan, cos, cot, sin, tan) +from sympy.logic.boolalg import Equivalent, Implies, Xor, And, to_cnf +from sympy.matrices import Matrix, SparseMatrix +from sympy.testing.pytest import (XFAIL, slow, raises, warns_deprecated_sympy, + _both_exp_pow) +import math + + +def test_int_1(): + z = 1 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_int_11(): + z = 11 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is True + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_int_12(): + z = 12 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is True + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is True + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_float_1(): + z = 1.0 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is None + assert ask(Q.rational(z)) is None + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is None + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is None + assert ask(Q.odd(z)) is None + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is None + assert ask(Q.composite(z)) is None + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = 7.2123 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is None + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is None + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + # test for issue #12168 + assert ask(Q.rational(math.pi)) is None + + +def test_zero_0(): + z = Integer(0) + assert ask(Q.nonzero(z)) is False + assert ask(Q.zero(z)) is True + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is True + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is True + + +def test_negativeone(): + z = Integer(-1) + assert ask(Q.nonzero(z)) is True + assert ask(Q.zero(z)) is False + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is True + assert ask(Q.rational(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is True + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is True + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_infinity(): + assert ask(Q.commutative(oo)) is True + assert ask(Q.integer(oo)) is False + assert ask(Q.rational(oo)) is False + assert ask(Q.algebraic(oo)) is False + assert ask(Q.real(oo)) is False + assert ask(Q.extended_real(oo)) is True + assert ask(Q.complex(oo)) is False + assert ask(Q.irrational(oo)) is False + assert ask(Q.imaginary(oo)) is False + assert ask(Q.positive(oo)) is False + assert ask(Q.extended_positive(oo)) is True + assert ask(Q.negative(oo)) is False + assert ask(Q.even(oo)) is False + assert ask(Q.odd(oo)) is False + assert ask(Q.finite(oo)) is False + assert ask(Q.infinite(oo)) is True + assert ask(Q.prime(oo)) is False + assert ask(Q.composite(oo)) is False + assert ask(Q.hermitian(oo)) is False + assert ask(Q.antihermitian(oo)) is False + assert ask(Q.positive_infinite(oo)) is True + assert ask(Q.negative_infinite(oo)) is False + + +def test_neg_infinity(): + mm = S.NegativeInfinity + assert ask(Q.commutative(mm)) is True + assert ask(Q.integer(mm)) is False + assert ask(Q.rational(mm)) is False + assert ask(Q.algebraic(mm)) is False + assert ask(Q.real(mm)) is False + assert ask(Q.extended_real(mm)) is True + assert ask(Q.complex(mm)) is False + assert ask(Q.irrational(mm)) is False + assert ask(Q.imaginary(mm)) is False + assert ask(Q.positive(mm)) is False + assert ask(Q.negative(mm)) is False + assert ask(Q.extended_negative(mm)) is True + assert ask(Q.even(mm)) is False + assert ask(Q.odd(mm)) is False + assert ask(Q.finite(mm)) is False + assert ask(Q.infinite(oo)) is True + assert ask(Q.prime(mm)) is False + assert ask(Q.composite(mm)) is False + assert ask(Q.hermitian(mm)) is False + assert ask(Q.antihermitian(mm)) is False + assert ask(Q.positive_infinite(-oo)) is False + assert ask(Q.negative_infinite(-oo)) is True + + +def test_complex_infinity(): + assert ask(Q.commutative(zoo)) is True + assert ask(Q.integer(zoo)) is False + assert ask(Q.rational(zoo)) is False + assert ask(Q.algebraic(zoo)) is False + assert ask(Q.real(zoo)) is False + assert ask(Q.extended_real(zoo)) is False + assert ask(Q.complex(zoo)) is False + assert ask(Q.irrational(zoo)) is False + assert ask(Q.imaginary(zoo)) is False + assert ask(Q.positive(zoo)) is False + assert ask(Q.negative(zoo)) is False + assert ask(Q.zero(zoo)) is False + assert ask(Q.nonzero(zoo)) is False + assert ask(Q.even(zoo)) is False + assert ask(Q.odd(zoo)) is False + assert ask(Q.finite(zoo)) is False + assert ask(Q.infinite(zoo)) is True + assert ask(Q.prime(zoo)) is False + assert ask(Q.composite(zoo)) is False + assert ask(Q.hermitian(zoo)) is False + assert ask(Q.antihermitian(zoo)) is False + assert ask(Q.positive_infinite(zoo)) is False + assert ask(Q.negative_infinite(zoo)) is False + + +def test_nan(): + nan = S.NaN + assert ask(Q.commutative(nan)) is True + assert ask(Q.integer(nan)) is None + assert ask(Q.rational(nan)) is None + assert ask(Q.algebraic(nan)) is None + assert ask(Q.real(nan)) is None + assert ask(Q.extended_real(nan)) is None + assert ask(Q.complex(nan)) is None + assert ask(Q.irrational(nan)) is None + assert ask(Q.imaginary(nan)) is None + assert ask(Q.positive(nan)) is None + assert ask(Q.nonzero(nan)) is None + assert ask(Q.zero(nan)) is None + assert ask(Q.even(nan)) is None + assert ask(Q.odd(nan)) is None + assert ask(Q.finite(nan)) is None + assert ask(Q.infinite(nan)) is None + assert ask(Q.prime(nan)) is None + assert ask(Q.composite(nan)) is None + assert ask(Q.hermitian(nan)) is None + assert ask(Q.antihermitian(nan)) is None + + +def test_Rational_number(): + r = Rational(3, 4) + assert ask(Q.commutative(r)) is True + assert ask(Q.integer(r)) is False + assert ask(Q.rational(r)) is True + assert ask(Q.real(r)) is True + assert ask(Q.complex(r)) is True + assert ask(Q.irrational(r)) is False + assert ask(Q.imaginary(r)) is False + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + assert ask(Q.even(r)) is False + assert ask(Q.odd(r)) is False + assert ask(Q.finite(r)) is True + assert ask(Q.prime(r)) is False + assert ask(Q.composite(r)) is False + assert ask(Q.hermitian(r)) is True + assert ask(Q.antihermitian(r)) is False + + r = Rational(1, 4) + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + + r = Rational(5, 4) + assert ask(Q.negative(r)) is False + assert ask(Q.positive(r)) is True + + r = Rational(5, 3) + assert ask(Q.positive(r)) is True + assert ask(Q.negative(r)) is False + + r = Rational(-3, 4) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + + r = Rational(-1, 4) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + + r = Rational(-5, 4) + assert ask(Q.negative(r)) is True + assert ask(Q.positive(r)) is False + + r = Rational(-5, 3) + assert ask(Q.positive(r)) is False + assert ask(Q.negative(r)) is True + + +def test_sqrt_2(): + z = sqrt(2) + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_pi(): + z = S.Pi + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = S.Pi + 1 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = 2*S.Pi + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = S.Pi ** 2 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + z = (1 + S.Pi) ** 2 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_E(): + z = S.Exp1 + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is False + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_GoldenRatio(): + z = S.GoldenRatio + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_TribonacciConstant(): + z = S.TribonacciConstant + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is True + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is True + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is True + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is True + assert ask(Q.antihermitian(z)) is False + + +def test_I(): + z = I + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is True + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is True + + z = 1 + I + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is False + + z = I*(1 + I) + assert ask(Q.commutative(z)) is True + assert ask(Q.integer(z)) is False + assert ask(Q.rational(z)) is False + assert ask(Q.algebraic(z)) is True + assert ask(Q.real(z)) is False + assert ask(Q.complex(z)) is True + assert ask(Q.irrational(z)) is False + assert ask(Q.imaginary(z)) is False + assert ask(Q.positive(z)) is False + assert ask(Q.negative(z)) is False + assert ask(Q.even(z)) is False + assert ask(Q.odd(z)) is False + assert ask(Q.finite(z)) is True + assert ask(Q.prime(z)) is False + assert ask(Q.composite(z)) is False + assert ask(Q.hermitian(z)) is False + assert ask(Q.antihermitian(z)) is False + + z = I**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (-I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (3*I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (1)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (-1)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (1+I)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (I)**(I+3) + assert ask(Q.imaginary(z)) is True + assert ask(Q.real(z)) is False + + z = (I)**(I+2) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (I)**(2) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + + z = (I)**(3) + assert ask(Q.imaginary(z)) is True + assert ask(Q.real(z)) is False + + z = (3)**(I) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is False + + z = (I)**(0) + assert ask(Q.imaginary(z)) is False + assert ask(Q.real(z)) is True + +def test_bounded(): + x, y, z = symbols('x,y,z') + a = x + y + x, y = a.args + assert ask(Q.finite(a), Q.positive_infinite(y)) is None + assert ask(Q.finite(x)) is None + assert ask(Q.finite(x), Q.finite(x)) is True + assert ask(Q.finite(x), Q.finite(y)) is None + assert ask(Q.finite(x), Q.complex(x)) is True + assert ask(Q.finite(x), Q.extended_real(x)) is None + + assert ask(Q.finite(x + 1)) is None + assert ask(Q.finite(x + 1), Q.finite(x)) is True + a = x + y + x, y = a.args + # B + B + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is True + assert ask(Q.finite(a), Q.positive(x) & Q.finite(y)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y)) is True + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y)) is True + assert ask(Q.finite(a), Q.positive(x) & Q.finite(y) + & ~Q.positive(y)) is True + assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) + & Q.positive(y)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & ~Q.positive(x) + & ~Q.positive(y)) is True + # B + U + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is False + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y)) is False + assert ask(Q.finite(a), Q.finite(x) + & Q.positive_infinite(y)) is False + assert ask(Q.finite(a), Q.positive(x) + & Q.positive_infinite(y)) is False + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) + & ~Q.positive(y)) is False + assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) + & Q.positive_infinite(y)) is False + assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & ~Q.finite(y) + & ~Q.positive(y)) is False + # B + ? + assert ask(Q.finite(a), Q.finite(x)) is None + assert ask(Q.finite(a), Q.positive(x)) is None + assert ask(Q.finite(a), Q.finite(x) + & Q.extended_positive(y)) is None + assert ask(Q.finite(a), Q.positive(x) + & Q.extended_positive(y)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.positive(y)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) + & Q.extended_positive(y)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) + & ~Q.positive(y)) is None + # U + U + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & ~Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.positive_infinite(y)) is False + assert ask(Q.finite(a), Q.positive_infinite(x) & ~Q.finite(y) + & ~Q.extended_positive(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.extended_positive(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & ~Q.extended_positive(x) & ~Q.extended_positive(y)) is False + # U + ? + assert ask(Q.finite(a), ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.extended_positive(x) + & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.extended_positive(x) + & Q.positive_infinite(y)) is False + assert ask(Q.finite(a), Q.extended_positive(x) + & ~Q.finite(y) & ~Q.extended_positive(y)) is None + assert ask(Q.finite(a), ~Q.extended_positive(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), ~Q.extended_positive(x) & ~Q.finite(y) + & ~Q.extended_positive(y)) is False + # ? + ? + assert ask(Q.finite(a)) is None + assert ask(Q.finite(a), Q.extended_positive(x)) is None + assert ask(Q.finite(a), Q.extended_positive(y)) is None + assert ask(Q.finite(a), Q.extended_positive(x) + & Q.extended_positive(y)) is None + assert ask(Q.finite(a), Q.extended_positive(x) + & ~Q.extended_positive(y)) is None + assert ask(Q.finite(a), ~Q.extended_positive(x) + & Q.extended_positive(y)) is None + assert ask(Q.finite(a), ~Q.extended_positive(x) + & ~Q.extended_positive(y)) is None + + x, y, z = symbols('x,y,z') + a = x + y + z + x, y, z = a.args + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.negative(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.finite(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.finite(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.extended_positive(y) + & Q.finite(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) + & Q.extended_negative(z)) is False + assert ask(Q.finite(a), Q.negative(x) + & Q.negative_infinite(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) + & Q.negative_infinite(z)) is None + assert ask(Q.finite(a), Q.negative(x) & + Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) + & Q.extended_positive(z)) is False + assert ask(Q.finite(a), Q.negative(x) & Q.extended_negative(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.extended_negative(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x)) is None + assert ask(Q.finite(a), Q.negative(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative(x) & Q.extended_positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.finite(z)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) + & Q.extended_negative(z)) is False + assert ask(Q.finite(a), Q.finite(x) + & Q.negative_infinite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.finite(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) + & Q.extended_positive(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.extended_negative(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.finite(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.extended_negative(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x)) is None + assert ask(Q.finite(a), Q.finite(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.extended_positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & Q.positive(z)) is True + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) + & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) + & Q.extended_negative(z)) is False + assert ask(Q.finite(a), Q.positive(x) + & Q.negative_infinite(y)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) + & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) + & Q.extended_positive(z)) is False + assert ask(Q.finite(a), Q.positive(x) & Q.extended_negative(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.extended_negative(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x)) is None + assert ask(Q.finite(a), Q.positive(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive(x) & Q.extended_positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y) & Q.negative_infinite(z)) is False + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y) & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y)& Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y) & Q.extended_negative(z)) is False + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.negative_infinite(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & ~Q.finite(y) & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & ~Q.finite(y) & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & ~Q.finite(y) & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & ~Q.finite(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.positive_infinite(y) & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.positive_infinite(y) & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.positive_infinite(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.extended_negative(y) & Q.extended_negative(z)) is False + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.extended_negative(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.negative_infinite(x) + & Q.extended_positive(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(z) + & ~Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) + & Q.positive_infinite(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_negative(y) + & Q.extended_negative(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_negative(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), ~Q.finite(x)) is None + assert ask(Q.finite(a), ~Q.finite(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.positive_infinite(y) & Q.positive_infinite(z)) is False + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.positive_infinite(y) & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.positive_infinite(y)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.positive_infinite(y) & Q.extended_positive(z)) is False + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.extended_negative(y) & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.extended_negative(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive_infinite(x)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.positive_infinite(x) + & Q.extended_positive(y) & Q.extended_positive(z)) is False + assert ask(Q.finite(a), Q.extended_negative(x) + & Q.extended_negative(y) & Q.extended_negative(z)) is None + assert ask(Q.finite(a), Q.extended_negative(x) + & Q.extended_negative(y)) is None + assert ask(Q.finite(a), Q.extended_negative(x) + & Q.extended_negative(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.extended_negative(x)) is None + assert ask(Q.finite(a), Q.extended_negative(x) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.extended_negative(x) + & Q.extended_positive(y) & Q.extended_positive(z)) is None + assert ask(Q.finite(a)) is None + assert ask(Q.finite(a), Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.extended_positive(y) + & Q.extended_positive(z)) is None + assert ask(Q.finite(a), Q.extended_positive(x) + & Q.extended_positive(y) & Q.extended_positive(z)) is None + + assert ask(Q.finite(2*x)) is None + assert ask(Q.finite(2*x), Q.finite(x)) is True + + x, y, z = symbols('x,y,z') + a = x*y + x, y = a.args + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is True + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is False + assert ask(Q.finite(a), Q.finite(x)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y)) is False + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is False + assert ask(Q.finite(a), ~Q.finite(x)) is None + assert ask(Q.finite(a), Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(y)) is None + assert ask(Q.finite(a)) is None + a = x*y*z + x, y, z = a.args + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & Q.finite(z)) is True + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & Q.finite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.finite(x) & Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(x)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y) + & Q.finite(z)) is False + assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & Q.finite(z)) is False + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) + & ~Q.finite(z)) is False + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(x)) is None + assert ask(Q.finite(a), Q.finite(y) & Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(y) & ~Q.finite(z)) is None + assert ask(Q.finite(a), Q.finite(y)) is None + assert ask(Q.finite(a), ~Q.finite(y) & Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(y) & ~Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(y)) is None + assert ask(Q.finite(a), Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(z)) is None + assert ask(Q.finite(a), ~Q.finite(z) & Q.extended_nonzero(x) + & Q.extended_nonzero(y) & Q.extended_nonzero(z)) is None + assert ask(Q.finite(a), Q.extended_nonzero(x) & ~Q.finite(y) + & Q.extended_nonzero(y) & ~Q.finite(z) + & Q.extended_nonzero(z)) is False + + x, y, z = symbols('x,y,z') + assert ask(Q.finite(x**2)) is None + assert ask(Q.finite(2**x)) is None + assert ask(Q.finite(2**x), Q.finite(x)) is True + assert ask(Q.finite(x**x)) is None + assert ask(Q.finite(S.Half ** x)) is None + assert ask(Q.finite(S.Half ** x), Q.extended_positive(x)) is True + assert ask(Q.finite(S.Half ** x), Q.extended_negative(x)) is None + assert ask(Q.finite(2**x), Q.extended_negative(x)) is True + assert ask(Q.finite(sqrt(x))) is None + assert ask(Q.finite(2**x), ~Q.finite(x)) is False + assert ask(Q.finite(x**2), ~Q.finite(x)) is False + + # sign function + assert ask(Q.finite(sign(x))) is True + assert ask(Q.finite(sign(x)), ~Q.finite(x)) is True + + # exponential functions + assert ask(Q.finite(log(x))) is None + assert ask(Q.finite(log(x)), Q.finite(x)) is None + assert ask(Q.finite(log(x)), ~Q.zero(x)) is True + assert ask(Q.finite(log(x)), Q.infinite(x)) is False + assert ask(Q.finite(log(x)), Q.zero(x)) is False + assert ask(Q.finite(exp(x))) is None + assert ask(Q.finite(exp(x)), Q.finite(x)) is True + assert ask(Q.finite(exp(2))) is True + + # trigonometric functions + assert ask(Q.finite(sin(x))) is True + assert ask(Q.finite(sin(x)), ~Q.finite(x)) is True + assert ask(Q.finite(cos(x))) is True + assert ask(Q.finite(cos(x)), ~Q.finite(x)) is True + assert ask(Q.finite(2*sin(x))) is True + assert ask(Q.finite(sin(x)**2)) is True + assert ask(Q.finite(cos(x)**2)) is True + assert ask(Q.finite(cos(x) + sin(x))) is True + + +@XFAIL +def test_bounded_xfail(): + """We need to support relations in ask for this to work""" + assert ask(Q.finite(sin(x)**x)) is True + assert ask(Q.finite(cos(x)**x)) is True + + +def test_commutative(): + """By default objects are Q.commutative that is why it returns True + for both key=True and key=False""" + assert ask(Q.commutative(x)) is True + assert ask(Q.commutative(x), ~Q.commutative(x)) is False + assert ask(Q.commutative(x), Q.complex(x)) is True + assert ask(Q.commutative(x), Q.imaginary(x)) is True + assert ask(Q.commutative(x), Q.real(x)) is True + assert ask(Q.commutative(x), Q.positive(x)) is True + assert ask(Q.commutative(x), ~Q.commutative(y)) is True + + assert ask(Q.commutative(2*x)) is True + assert ask(Q.commutative(2*x), ~Q.commutative(x)) is False + + assert ask(Q.commutative(x + 1)) is True + assert ask(Q.commutative(x + 1), ~Q.commutative(x)) is False + + assert ask(Q.commutative(x**2)) is True + assert ask(Q.commutative(x**2), ~Q.commutative(x)) is False + + assert ask(Q.commutative(log(x))) is True + + +@_both_exp_pow +def test_complex(): + assert ask(Q.complex(x)) is None + assert ask(Q.complex(x), Q.complex(x)) is True + assert ask(Q.complex(x), Q.complex(y)) is None + assert ask(Q.complex(x), ~Q.complex(x)) is False + assert ask(Q.complex(x), Q.real(x)) is True + assert ask(Q.complex(x), ~Q.real(x)) is None + assert ask(Q.complex(x), Q.rational(x)) is True + assert ask(Q.complex(x), Q.irrational(x)) is True + assert ask(Q.complex(x), Q.positive(x)) is True + assert ask(Q.complex(x), Q.imaginary(x)) is True + assert ask(Q.complex(x), Q.algebraic(x)) is True + + # a+b + assert ask(Q.complex(x + 1), Q.complex(x)) is True + assert ask(Q.complex(x + 1), Q.real(x)) is True + assert ask(Q.complex(x + 1), Q.rational(x)) is True + assert ask(Q.complex(x + 1), Q.irrational(x)) is True + assert ask(Q.complex(x + 1), Q.imaginary(x)) is True + assert ask(Q.complex(x + 1), Q.integer(x)) is True + assert ask(Q.complex(x + 1), Q.even(x)) is True + assert ask(Q.complex(x + 1), Q.odd(x)) is True + assert ask(Q.complex(x + y), Q.complex(x) & Q.complex(y)) is True + assert ask(Q.complex(x + y), Q.real(x) & Q.imaginary(y)) is True + + # a*x +b + assert ask(Q.complex(2*x + 1), Q.complex(x)) is True + assert ask(Q.complex(2*x + 1), Q.real(x)) is True + assert ask(Q.complex(2*x + 1), Q.positive(x)) is True + assert ask(Q.complex(2*x + 1), Q.rational(x)) is True + assert ask(Q.complex(2*x + 1), Q.irrational(x)) is True + assert ask(Q.complex(2*x + 1), Q.imaginary(x)) is True + assert ask(Q.complex(2*x + 1), Q.integer(x)) is True + assert ask(Q.complex(2*x + 1), Q.even(x)) is True + assert ask(Q.complex(2*x + 1), Q.odd(x)) is True + + # x**2 + assert ask(Q.complex(x**2), Q.complex(x)) is True + assert ask(Q.complex(x**2), Q.real(x)) is True + assert ask(Q.complex(x**2), Q.positive(x)) is True + assert ask(Q.complex(x**2), Q.rational(x)) is True + assert ask(Q.complex(x**2), Q.irrational(x)) is True + assert ask(Q.complex(x**2), Q.imaginary(x)) is True + assert ask(Q.complex(x**2), Q.integer(x)) is True + assert ask(Q.complex(x**2), Q.even(x)) is True + assert ask(Q.complex(x**2), Q.odd(x)) is True + + # 2**x + assert ask(Q.complex(2**x), Q.complex(x)) is True + assert ask(Q.complex(2**x), Q.real(x)) is True + assert ask(Q.complex(2**x), Q.positive(x)) is True + assert ask(Q.complex(2**x), Q.rational(x)) is True + assert ask(Q.complex(2**x), Q.irrational(x)) is True + assert ask(Q.complex(2**x), Q.imaginary(x)) is True + assert ask(Q.complex(2**x), Q.integer(x)) is True + assert ask(Q.complex(2**x), Q.even(x)) is True + assert ask(Q.complex(2**x), Q.odd(x)) is True + assert ask(Q.complex(x**y), Q.complex(x) & Q.complex(y)) is True + + # trigonometric expressions + assert ask(Q.complex(sin(x))) is True + assert ask(Q.complex(sin(2*x + 1))) is True + assert ask(Q.complex(cos(x))) is True + assert ask(Q.complex(cos(2*x + 1))) is True + + # exponential + assert ask(Q.complex(exp(x))) is True + assert ask(Q.complex(exp(x))) is True + + # Q.complexes + assert ask(Q.complex(Abs(x))) is True + assert ask(Q.complex(re(x))) is True + assert ask(Q.complex(im(x))) is True + + +def test_even_query(): + assert ask(Q.even(x)) is None + assert ask(Q.even(x), Q.integer(x)) is None + assert ask(Q.even(x), ~Q.integer(x)) is False + assert ask(Q.even(x), Q.rational(x)) is None + assert ask(Q.even(x), Q.positive(x)) is None + + assert ask(Q.even(2*x)) is None + assert ask(Q.even(2*x), Q.integer(x)) is True + assert ask(Q.even(2*x), Q.even(x)) is True + assert ask(Q.even(2*x), Q.irrational(x)) is False + assert ask(Q.even(2*x), Q.odd(x)) is True + assert ask(Q.even(2*x), ~Q.integer(x)) is None + assert ask(Q.even(3*x), Q.integer(x)) is None + assert ask(Q.even(3*x), Q.even(x)) is True + assert ask(Q.even(3*x), Q.odd(x)) is False + + assert ask(Q.even(x + 1), Q.odd(x)) is True + assert ask(Q.even(x + 1), Q.even(x)) is False + assert ask(Q.even(x + 2), Q.odd(x)) is False + assert ask(Q.even(x + 2), Q.even(x)) is True + assert ask(Q.even(7 - x), Q.odd(x)) is True + assert ask(Q.even(7 + x), Q.odd(x)) is True + assert ask(Q.even(x + y), Q.odd(x) & Q.odd(y)) is True + assert ask(Q.even(x + y), Q.odd(x) & Q.even(y)) is False + assert ask(Q.even(x + y), Q.even(x) & Q.even(y)) is True + + assert ask(Q.even(2*x + 1), Q.integer(x)) is False + assert ask(Q.even(2*x*y), Q.rational(x) & Q.rational(x)) is None + assert ask(Q.even(2*x*y), Q.irrational(x) & Q.irrational(x)) is None + + assert ask(Q.even(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is True + assert ask(Q.even(x + y + z + t), + Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None + + assert ask(Q.even(Abs(x)), Q.even(x)) is True + assert ask(Q.even(Abs(x)), ~Q.even(x)) is None + assert ask(Q.even(re(x)), Q.even(x)) is True + assert ask(Q.even(re(x)), ~Q.even(x)) is None + assert ask(Q.even(im(x)), Q.even(x)) is True + assert ask(Q.even(im(x)), Q.real(x)) is True + + assert ask(Q.even((-1)**n), Q.integer(n)) is False + + assert ask(Q.even(k**2), Q.even(k)) is True + assert ask(Q.even(n**2), Q.odd(n)) is False + assert ask(Q.even(2**k), Q.even(k)) is None + assert ask(Q.even(x**2)) is None + + assert ask(Q.even(k**m), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.even(n**m), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is False + + assert ask(Q.even(k**p), Q.even(k) & Q.integer(p) & Q.positive(p)) is True + assert ask(Q.even(n**p), Q.odd(n) & Q.integer(p) & Q.positive(p)) is False + + assert ask(Q.even(m**k), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.even(p**k), Q.even(k) & Q.integer(p) & Q.positive(p)) is None + + assert ask(Q.even(m**n), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.even(p**n), Q.odd(n) & Q.integer(p) & Q.positive(p)) is None + + assert ask(Q.even(k**x), Q.even(k)) is None + assert ask(Q.even(n**x), Q.odd(n)) is None + + assert ask(Q.even(x*y), Q.integer(x) & Q.integer(y)) is None + assert ask(Q.even(x*x), Q.integer(x)) is None + assert ask(Q.even(x*(x + y)), Q.integer(x) & Q.odd(y)) is True + assert ask(Q.even(x*(x + y)), Q.integer(x) & Q.even(y)) is None + + +@XFAIL +def test_evenness_in_ternary_integer_product_with_odd(): + # Tests that oddness inference is independent of term ordering. + # Term ordering at the point of testing depends on SymPy's symbol order, so + # we try to force a different order by modifying symbol names. + assert ask(Q.even(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is True + assert ask(Q.even(y*x*(x + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is True + + +def test_evenness_in_ternary_integer_product_with_even(): + assert ask(Q.even(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.even(z)) is None + + +def test_extended_real(): + assert ask(Q.extended_real(x), Q.positive_infinite(x)) is True + assert ask(Q.extended_real(x), Q.positive(x)) is True + assert ask(Q.extended_real(x), Q.zero(x)) is True + assert ask(Q.extended_real(x), Q.negative(x)) is True + assert ask(Q.extended_real(x), Q.negative_infinite(x)) is True + + assert ask(Q.extended_real(-x), Q.positive(x)) is True + assert ask(Q.extended_real(-x), Q.negative(x)) is True + + assert ask(Q.extended_real(x + S.Infinity), Q.real(x)) is True + + assert ask(Q.extended_real(x), Q.infinite(x)) is None + + +@_both_exp_pow +def test_rational(): + assert ask(Q.rational(x), Q.integer(x)) is True + assert ask(Q.rational(x), Q.irrational(x)) is False + assert ask(Q.rational(x), Q.real(x)) is None + assert ask(Q.rational(x), Q.positive(x)) is None + assert ask(Q.rational(x), Q.negative(x)) is None + assert ask(Q.rational(x), Q.nonzero(x)) is None + assert ask(Q.rational(x), ~Q.algebraic(x)) is False + + assert ask(Q.rational(2*x), Q.rational(x)) is True + assert ask(Q.rational(2*x), Q.integer(x)) is True + assert ask(Q.rational(2*x), Q.even(x)) is True + assert ask(Q.rational(2*x), Q.odd(x)) is True + assert ask(Q.rational(2*x), Q.irrational(x)) is False + + assert ask(Q.rational(x/2), Q.rational(x)) is True + assert ask(Q.rational(x/2), Q.integer(x)) is True + assert ask(Q.rational(x/2), Q.even(x)) is True + assert ask(Q.rational(x/2), Q.odd(x)) is True + assert ask(Q.rational(x/2), Q.irrational(x)) is False + + assert ask(Q.rational(1/x), Q.rational(x)) is True + assert ask(Q.rational(1/x), Q.integer(x)) is True + assert ask(Q.rational(1/x), Q.even(x)) is True + assert ask(Q.rational(1/x), Q.odd(x)) is True + assert ask(Q.rational(1/x), Q.irrational(x)) is False + + assert ask(Q.rational(2/x), Q.rational(x)) is True + assert ask(Q.rational(2/x), Q.integer(x)) is True + assert ask(Q.rational(2/x), Q.even(x)) is True + assert ask(Q.rational(2/x), Q.odd(x)) is True + assert ask(Q.rational(2/x), Q.irrational(x)) is False + + assert ask(Q.rational(x), ~Q.algebraic(x)) is False + + # with multiple symbols + assert ask(Q.rational(x*y), Q.irrational(x) & Q.irrational(y)) is None + assert ask(Q.rational(y/x), Q.rational(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.integer(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.even(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.odd(x) & Q.rational(y)) is True + assert ask(Q.rational(y/x), Q.irrational(x) & Q.rational(y)) is False + + for f in [exp, sin, tan, asin, atan, cos]: + assert ask(Q.rational(f(7))) is False + assert ask(Q.rational(f(7, evaluate=False))) is False + assert ask(Q.rational(f(0, evaluate=False))) is True + assert ask(Q.rational(f(x)), Q.rational(x)) is None + assert ask(Q.rational(f(x)), Q.rational(x) & Q.nonzero(x)) is False + + for g in [log, acos]: + assert ask(Q.rational(g(7))) is False + assert ask(Q.rational(g(7, evaluate=False))) is False + assert ask(Q.rational(g(1, evaluate=False))) is True + assert ask(Q.rational(g(x)), Q.rational(x)) is None + assert ask(Q.rational(g(x)), Q.rational(x) & Q.nonzero(x - 1)) is False + + for h in [cot, acot]: + assert ask(Q.rational(h(7))) is False + assert ask(Q.rational(h(7, evaluate=False))) is False + assert ask(Q.rational(h(x)), Q.rational(x)) is False + + +def test_hermitian(): + assert ask(Q.hermitian(x)) is None + assert ask(Q.hermitian(x), Q.antihermitian(x)) is None + assert ask(Q.hermitian(x), Q.imaginary(x)) is False + assert ask(Q.hermitian(x), Q.prime(x)) is True + assert ask(Q.hermitian(x), Q.real(x)) is True + assert ask(Q.hermitian(x), Q.zero(x)) is True + + assert ask(Q.hermitian(x + 1), Q.antihermitian(x)) is None + assert ask(Q.hermitian(x + 1), Q.complex(x)) is None + assert ask(Q.hermitian(x + 1), Q.hermitian(x)) is True + assert ask(Q.hermitian(x + 1), Q.imaginary(x)) is False + assert ask(Q.hermitian(x + 1), Q.real(x)) is True + assert ask(Q.hermitian(x + I), Q.antihermitian(x)) is None + assert ask(Q.hermitian(x + I), Q.complex(x)) is None + assert ask(Q.hermitian(x + I), Q.hermitian(x)) is False + assert ask(Q.hermitian(x + I), Q.imaginary(x)) is None + assert ask(Q.hermitian(x + I), Q.real(x)) is False + assert ask( + Q.hermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y)) is None + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None + assert ask( + Q.hermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is None + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is None + assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.real(y)) is None + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.hermitian(y)) is True + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is False + assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.real(y)) is True + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is None + assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.hermitian(x + y), Q.real(x) & Q.complex(y)) is None + assert ask(Q.hermitian(x + y), Q.real(x) & Q.real(y)) is True + + assert ask(Q.hermitian(I*x), Q.antihermitian(x)) is True + assert ask(Q.hermitian(I*x), Q.complex(x)) is None + assert ask(Q.hermitian(I*x), Q.hermitian(x)) is False + assert ask(Q.hermitian(I*x), Q.imaginary(x)) is True + assert ask(Q.hermitian(I*x), Q.real(x)) is False + assert ask(Q.hermitian(x*y), Q.hermitian(x) & Q.real(y)) is True + + assert ask( + Q.hermitian(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True + assert ask(Q.hermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is False + assert ask(Q.hermitian(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is None + assert ask(Q.hermitian(x + y + z), + Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is None + + assert ask(Q.antihermitian(x)) is None + assert ask(Q.antihermitian(x), Q.real(x)) is False + assert ask(Q.antihermitian(x), Q.prime(x)) is False + + assert ask(Q.antihermitian(x + 1), Q.antihermitian(x)) is False + assert ask(Q.antihermitian(x + 1), Q.complex(x)) is None + assert ask(Q.antihermitian(x + 1), Q.hermitian(x)) is None + assert ask(Q.antihermitian(x + 1), Q.imaginary(x)) is False + assert ask(Q.antihermitian(x + 1), Q.real(x)) is None + assert ask(Q.antihermitian(x + I), Q.antihermitian(x)) is True + assert ask(Q.antihermitian(x + I), Q.complex(x)) is None + assert ask(Q.antihermitian(x + I), Q.hermitian(x)) is None + assert ask(Q.antihermitian(x + I), Q.imaginary(x)) is True + assert ask(Q.antihermitian(x + I), Q.real(x)) is False + assert ask(Q.antihermitian(x), Q.zero(x)) is True + + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y) + ) is True + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is None + assert ask( + Q.antihermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is True + assert ask(Q.antihermitian(x + y), Q.antihermitian(x) & Q.real(y) + ) is False + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.hermitian(y) + ) is None + assert ask( + Q.antihermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is None + assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.real(y)) is None + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is True + assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.antihermitian(x + y), Q.real(x) & Q.complex(y)) is None + assert ask(Q.antihermitian(x + y), Q.real(x) & Q.real(y)) is None + + assert ask(Q.antihermitian(I*x), Q.real(x)) is True + assert ask(Q.antihermitian(I*x), Q.antihermitian(x)) is False + assert ask(Q.antihermitian(I*x), Q.complex(x)) is None + assert ask(Q.antihermitian(x*y), Q.antihermitian(x) & Q.real(y)) is True + + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.real(z)) is None + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is None + assert ask(Q.antihermitian(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False + assert ask(Q.antihermitian(x + y + z), + Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is True + + +@_both_exp_pow +def test_imaginary(): + assert ask(Q.imaginary(x)) is None + assert ask(Q.imaginary(x), Q.real(x)) is False + assert ask(Q.imaginary(x), Q.prime(x)) is False + + assert ask(Q.imaginary(x + 1), Q.real(x)) is False + assert ask(Q.imaginary(x + 1), Q.imaginary(x)) is False + assert ask(Q.imaginary(x + I), Q.real(x)) is False + assert ask(Q.imaginary(x + I), Q.imaginary(x)) is True + assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.imaginary(y)) is True + assert ask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False + assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.real(y)) is False + assert ask(Q.imaginary(x + y), Q.complex(x) & Q.real(y)) is None + assert ask( + Q.imaginary(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is False + assert ask(Q.imaginary(x + y + z), + Q.real(x) & Q.real(y) & Q.imaginary(z)) is None + assert ask(Q.imaginary(x + y + z), + Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False + + assert ask(Q.imaginary(I*x), Q.real(x)) is True + assert ask(Q.imaginary(I*x), Q.imaginary(x)) is False + assert ask(Q.imaginary(I*x), Q.complex(x)) is None + assert ask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True + assert ask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False + + assert ask(Q.imaginary(I**x), Q.negative(x)) is None + assert ask(Q.imaginary(I**x), Q.positive(x)) is None + assert ask(Q.imaginary(I**x), Q.even(x)) is False + assert ask(Q.imaginary(I**x), Q.odd(x)) is True + assert ask(Q.imaginary(I**x), Q.imaginary(x)) is False + assert ask(Q.imaginary((2*I)**x), Q.imaginary(x)) is False + assert ask(Q.imaginary(x**0), Q.imaginary(x)) is False + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.real(y)) is None + assert ask(Q.imaginary(x**y), Q.real(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**y), Q.real(x) & Q.real(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.integer(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(y) & Q.integer(x)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.odd(y)) is True + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.rational(y)) is None + assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.even(y)) is False + + assert ask(Q.imaginary(x**y), Q.real(x) & Q.integer(y)) is False + assert ask(Q.imaginary(x**y), Q.positive(x) & Q.real(y)) is False + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.real(y)) is None + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.real(y) & ~Q.rational(y)) is False + assert ask(Q.imaginary(x**y), Q.integer(x) & Q.imaginary(y)) is None + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y) & Q.integer(2*y)) is True + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y) & ~Q.integer(2*y)) is False + assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y)) is None + assert ask(Q.imaginary(x**y), Q.real(x) & Q.rational(y) & ~Q.integer(2*y)) is False + assert ask(Q.imaginary(x**y), Q.real(x) & Q.rational(y) & Q.integer(2*y)) is None + + # logarithm + assert ask(Q.imaginary(log(I))) is True + assert ask(Q.imaginary(log(2*I))) is False + assert ask(Q.imaginary(log(I + 1))) is False + assert ask(Q.imaginary(log(x)), Q.complex(x)) is None + assert ask(Q.imaginary(log(x)), Q.imaginary(x)) is None + assert ask(Q.imaginary(log(x)), Q.positive(x)) is False + assert ask(Q.imaginary(log(exp(x))), Q.complex(x)) is None + assert ask(Q.imaginary(log(exp(x))), Q.imaginary(x)) is None # zoo/I/a+I*b + assert ask(Q.imaginary(log(exp(I)))) is True + + # exponential + assert ask(Q.imaginary(exp(x)**x), Q.imaginary(x)) is False + eq = Pow(exp(pi*I*x, evaluate=False), x, evaluate=False) + assert ask(Q.imaginary(eq), Q.even(x)) is False + eq = Pow(exp(pi*I*x/2, evaluate=False), x, evaluate=False) + assert ask(Q.imaginary(eq), Q.odd(x)) is True + assert ask(Q.imaginary(exp(3*I*pi*x)**x), Q.integer(x)) is False + assert ask(Q.imaginary(exp(2*pi*I, evaluate=False))) is False + assert ask(Q.imaginary(exp(pi*I/2, evaluate=False))) is True + + # issue 7886 + assert ask(Q.imaginary(Pow(x, Rational(1, 4))), Q.real(x) & Q.negative(x)) is False + + +def test_integer(): + assert ask(Q.integer(x)) is None + assert ask(Q.integer(x), Q.integer(x)) is True + assert ask(Q.integer(x), ~Q.integer(x)) is False + assert ask(Q.integer(x), ~Q.real(x)) is False + assert ask(Q.integer(x), ~Q.positive(x)) is None + assert ask(Q.integer(x), Q.even(x) | Q.odd(x)) is True + + assert ask(Q.integer(2*x), Q.integer(x)) is True + assert ask(Q.integer(2*x), Q.even(x)) is True + assert ask(Q.integer(2*x), Q.prime(x)) is True + assert ask(Q.integer(2*x), Q.rational(x)) is None + assert ask(Q.integer(2*x), Q.real(x)) is None + assert ask(Q.integer(sqrt(2)*x), Q.integer(x)) is False + assert ask(Q.integer(sqrt(2)*x), Q.irrational(x)) is None + + assert ask(Q.integer(x/2), Q.odd(x)) is False + assert ask(Q.integer(x/2), Q.even(x)) is True + assert ask(Q.integer(x/3), Q.odd(x)) is None + assert ask(Q.integer(x/3), Q.even(x)) is None + + +def test_negative(): + assert ask(Q.negative(x), Q.negative(x)) is True + assert ask(Q.negative(x), Q.positive(x)) is False + assert ask(Q.negative(x), ~Q.real(x)) is False + assert ask(Q.negative(x), Q.prime(x)) is False + assert ask(Q.negative(x), ~Q.prime(x)) is None + + assert ask(Q.negative(-x), Q.positive(x)) is True + assert ask(Q.negative(-x), ~Q.positive(x)) is None + assert ask(Q.negative(-x), Q.negative(x)) is False + assert ask(Q.negative(-x), Q.positive(x)) is True + + assert ask(Q.negative(x - 1), Q.negative(x)) is True + assert ask(Q.negative(x + y)) is None + assert ask(Q.negative(x + y), Q.negative(x)) is None + assert ask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True + assert ask(Q.negative(x + y), Q.negative(x) & Q.nonpositive(y)) is True + assert ask(Q.negative(2 + I)) is False + # although this could be False, it is representative of expressions + # that don't evaluate to a zero with precision + assert ask(Q.negative(cos(I)**2 + sin(I)**2 - 1)) is None + assert ask(Q.negative(-I + I*(cos(2)**2 + sin(2)**2))) is None + + assert ask(Q.negative(x**2)) is None + assert ask(Q.negative(x**2), Q.real(x)) is False + assert ask(Q.negative(x**1.4), Q.real(x)) is None + + assert ask(Q.negative(x**I), Q.positive(x)) is None + + assert ask(Q.negative(x*y)) is None + assert ask(Q.negative(x*y), Q.positive(x) & Q.positive(y)) is False + assert ask(Q.negative(x*y), Q.positive(x) & Q.negative(y)) is True + assert ask(Q.negative(x*y), Q.complex(x) & Q.complex(y)) is None + + assert ask(Q.negative(x**y)) is None + assert ask(Q.negative(x**y), Q.negative(x) & Q.even(y)) is False + assert ask(Q.negative(x**y), Q.negative(x) & Q.odd(y)) is True + assert ask(Q.negative(x**y), Q.positive(x) & Q.integer(y)) is False + + assert ask(Q.negative(Abs(x))) is False + + +def test_nonzero(): + assert ask(Q.nonzero(x)) is None + assert ask(Q.nonzero(x), Q.real(x)) is None + assert ask(Q.nonzero(x), Q.positive(x)) is True + assert ask(Q.nonzero(x), Q.negative(x)) is True + assert ask(Q.nonzero(x), Q.negative(x) | Q.positive(x)) is True + + assert ask(Q.nonzero(x + y)) is None + assert ask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True + assert ask(Q.nonzero(x + y), Q.positive(x) & Q.negative(y)) is None + assert ask(Q.nonzero(x + y), Q.negative(x) & Q.negative(y)) is True + + assert ask(Q.nonzero(2*x)) is None + assert ask(Q.nonzero(2*x), Q.positive(x)) is True + assert ask(Q.nonzero(2*x), Q.negative(x)) is True + assert ask(Q.nonzero(x*y), Q.nonzero(x)) is None + assert ask(Q.nonzero(x*y), Q.nonzero(x) & Q.nonzero(y)) is True + + assert ask(Q.nonzero(x**y), Q.nonzero(x)) is True + + assert ask(Q.nonzero(Abs(x))) is None + assert ask(Q.nonzero(Abs(x)), Q.nonzero(x)) is True + + assert ask(Q.nonzero(log(exp(2*I)))) is False + # although this could be False, it is representative of expressions + # that don't evaluate to a zero with precision + assert ask(Q.nonzero(cos(1)**2 + sin(1)**2 - 1)) is None + + +def test_zero(): + assert ask(Q.zero(x)) is None + assert ask(Q.zero(x), Q.real(x)) is None + assert ask(Q.zero(x), Q.positive(x)) is False + assert ask(Q.zero(x), Q.negative(x)) is False + assert ask(Q.zero(x), Q.negative(x) | Q.positive(x)) is False + + assert ask(Q.zero(x), Q.nonnegative(x) & Q.nonpositive(x)) is True + + assert ask(Q.zero(x + y)) is None + assert ask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False + assert ask(Q.zero(x + y), Q.positive(x) & Q.negative(y)) is None + assert ask(Q.zero(x + y), Q.negative(x) & Q.negative(y)) is False + + assert ask(Q.zero(2*x)) is None + assert ask(Q.zero(2*x), Q.positive(x)) is False + assert ask(Q.zero(2*x), Q.negative(x)) is False + assert ask(Q.zero(x*y), Q.nonzero(x)) is None + + assert ask(Q.zero(Abs(x))) is None + assert ask(Q.zero(Abs(x)), Q.zero(x)) is True + + assert ask(Q.integer(x), Q.zero(x)) is True + assert ask(Q.even(x), Q.zero(x)) is True + assert ask(Q.odd(x), Q.zero(x)) is False + assert ask(Q.zero(x), Q.even(x)) is None + assert ask(Q.zero(x), Q.odd(x)) is False + assert ask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True + + +def test_odd_query(): + assert ask(Q.odd(x)) is None + assert ask(Q.odd(x), Q.odd(x)) is True + assert ask(Q.odd(x), Q.integer(x)) is None + assert ask(Q.odd(x), ~Q.integer(x)) is False + assert ask(Q.odd(x), Q.rational(x)) is None + assert ask(Q.odd(x), Q.positive(x)) is None + + assert ask(Q.odd(-x), Q.odd(x)) is True + + assert ask(Q.odd(2*x)) is None + assert ask(Q.odd(2*x), Q.integer(x)) is False + assert ask(Q.odd(2*x), Q.odd(x)) is False + assert ask(Q.odd(2*x), Q.irrational(x)) is False + assert ask(Q.odd(2*x), ~Q.integer(x)) is None + assert ask(Q.odd(3*x), Q.integer(x)) is None + + assert ask(Q.odd(x/3), Q.odd(x)) is None + assert ask(Q.odd(x/3), Q.even(x)) is None + + assert ask(Q.odd(x + 1), Q.even(x)) is True + assert ask(Q.odd(x + 2), Q.even(x)) is False + assert ask(Q.odd(x + 2), Q.odd(x)) is True + assert ask(Q.odd(3 - x), Q.odd(x)) is False + assert ask(Q.odd(3 - x), Q.even(x)) is True + assert ask(Q.odd(3 + x), Q.odd(x)) is False + assert ask(Q.odd(3 + x), Q.even(x)) is True + assert ask(Q.odd(x + y), Q.odd(x) & Q.odd(y)) is False + assert ask(Q.odd(x + y), Q.odd(x) & Q.even(y)) is True + assert ask(Q.odd(x - y), Q.even(x) & Q.odd(y)) is True + assert ask(Q.odd(x - y), Q.odd(x) & Q.odd(y)) is False + + assert ask(Q.odd(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is False + assert ask(Q.odd(x + y + z + t), + Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None + + assert ask(Q.odd(2*x + 1), Q.integer(x)) is True + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.odd(y)) is True + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.even(y)) is False + assert ask(Q.odd(2*x + y), Q.integer(x) & Q.integer(y)) is None + assert ask(Q.odd(x*y), Q.odd(x) & Q.even(y)) is False + assert ask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True + assert ask(Q.odd(2*x*y), Q.rational(x) & Q.rational(x)) is None + assert ask(Q.odd(2*x*y), Q.irrational(x) & Q.irrational(x)) is None + + assert ask(Q.odd(Abs(x)), Q.odd(x)) is True + + assert ask(Q.odd((-1)**n), Q.integer(n)) is True + + assert ask(Q.odd(k**2), Q.even(k)) is False + assert ask(Q.odd(n**2), Q.odd(n)) is True + assert ask(Q.odd(3**k), Q.even(k)) is None + + assert ask(Q.odd(k**m), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.odd(n**m), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is True + + assert ask(Q.odd(k**p), Q.even(k) & Q.integer(p) & Q.positive(p)) is False + assert ask(Q.odd(n**p), Q.odd(n) & Q.integer(p) & Q.positive(p)) is True + + assert ask(Q.odd(m**k), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.odd(p**k), Q.even(k) & Q.integer(p) & Q.positive(p)) is None + + assert ask(Q.odd(m**n), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is None + assert ask(Q.odd(p**n), Q.odd(n) & Q.integer(p) & Q.positive(p)) is None + + assert ask(Q.odd(k**x), Q.even(k)) is None + assert ask(Q.odd(n**x), Q.odd(n)) is None + + assert ask(Q.odd(x*y), Q.integer(x) & Q.integer(y)) is None + assert ask(Q.odd(x*x), Q.integer(x)) is None + assert ask(Q.odd(x*(x + y)), Q.integer(x) & Q.odd(y)) is False + assert ask(Q.odd(x*(x + y)), Q.integer(x) & Q.even(y)) is None + + +@XFAIL +def test_oddness_in_ternary_integer_product_with_odd(): + # Tests that oddness inference is independent of term ordering. + # Term ordering at the point of testing depends on SymPy's symbol order, so + # we try to force a different order by modifying symbol names. + assert ask(Q.odd(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is False + assert ask(Q.odd(y*x*(x + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is False + + +def test_oddness_in_ternary_integer_product_with_even(): + assert ask(Q.odd(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.even(z)) is None + + +def test_prime(): + assert ask(Q.prime(x), Q.prime(x)) is True + assert ask(Q.prime(x), ~Q.prime(x)) is False + assert ask(Q.prime(x), Q.integer(x)) is None + assert ask(Q.prime(x), ~Q.integer(x)) is False + + assert ask(Q.prime(2*x), Q.integer(x)) is None + assert ask(Q.prime(x*y)) is None + assert ask(Q.prime(x*y), Q.prime(x)) is None + assert ask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None + assert ask(Q.prime(4*x), Q.integer(x)) is False + assert ask(Q.prime(4*x)) is None + + assert ask(Q.prime(x**2), Q.integer(x)) is False + assert ask(Q.prime(x**2), Q.prime(x)) is False + assert ask(Q.prime(x**y), Q.integer(x) & Q.integer(y)) is False + + +@_both_exp_pow +def test_positive(): + assert ask(Q.positive(cos(I) ** 2 + sin(I) ** 2 - 1)) is None + assert ask(Q.positive(x), Q.positive(x)) is True + assert ask(Q.positive(x), Q.negative(x)) is False + assert ask(Q.positive(x), Q.nonzero(x)) is None + + assert ask(Q.positive(-x), Q.positive(x)) is False + assert ask(Q.positive(-x), Q.negative(x)) is True + + assert ask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True + assert ask(Q.positive(x + y), Q.positive(x) & Q.nonnegative(y)) is True + assert ask(Q.positive(x + y), Q.positive(x) & Q.negative(y)) is None + assert ask(Q.positive(x + y), Q.positive(x) & Q.imaginary(y)) is False + + assert ask(Q.positive(2*x), Q.positive(x)) is True + assumptions = Q.positive(x) & Q.negative(y) & Q.negative(z) & Q.positive(w) + assert ask(Q.positive(x*y*z)) is None + assert ask(Q.positive(x*y*z), assumptions) is True + assert ask(Q.positive(-x*y*z), assumptions) is False + + assert ask(Q.positive(x**I), Q.positive(x)) is None + + assert ask(Q.positive(x**2), Q.positive(x)) is True + assert ask(Q.positive(x**2), Q.negative(x)) is True + assert ask(Q.positive(x**3), Q.negative(x)) is False + assert ask(Q.positive(1/(1 + x**2)), Q.real(x)) is True + assert ask(Q.positive(2**I)) is False + assert ask(Q.positive(2 + I)) is False + # although this could be False, it is representative of expressions + # that don't evaluate to a zero with precision + assert ask(Q.positive(cos(I)**2 + sin(I)**2 - 1)) is None + assert ask(Q.positive(-I + I*(cos(2)**2 + sin(2)**2))) is None + + #exponential + assert ask(Q.positive(exp(x)), Q.real(x)) is True + assert ask(~Q.negative(exp(x)), Q.real(x)) is True + assert ask(Q.positive(x + exp(x)), Q.real(x)) is None + assert ask(Q.positive(exp(x)), Q.imaginary(x)) is None + assert ask(Q.positive(exp(2*pi*I, evaluate=False)), Q.imaginary(x)) is True + assert ask(Q.negative(exp(pi*I, evaluate=False)), Q.imaginary(x)) is True + assert ask(Q.positive(exp(x*pi*I)), Q.even(x)) is True + assert ask(Q.positive(exp(x*pi*I)), Q.odd(x)) is False + assert ask(Q.positive(exp(x*pi*I)), Q.real(x)) is None + + # logarithm + assert ask(Q.positive(log(x)), Q.imaginary(x)) is False + assert ask(Q.positive(log(x)), Q.negative(x)) is False + assert ask(Q.positive(log(x)), Q.positive(x)) is None + assert ask(Q.positive(log(x + 2)), Q.positive(x)) is True + + # factorial + assert ask(Q.positive(factorial(x)), Q.integer(x) & Q.positive(x)) + assert ask(Q.positive(factorial(x)), Q.integer(x)) is None + + #absolute value + assert ask(Q.positive(Abs(x))) is None # Abs(0) = 0 + assert ask(Q.positive(Abs(x)), Q.positive(x)) is True + + +def test_nonpositive(): + assert ask(Q.nonpositive(-1)) + assert ask(Q.nonpositive(0)) + assert ask(Q.nonpositive(1)) is False + assert ask(~Q.positive(x), Q.nonpositive(x)) + assert ask(Q.nonpositive(x), Q.positive(x)) is False + assert ask(Q.nonpositive(sqrt(-1))) is False + assert ask(Q.nonpositive(x), Q.imaginary(x)) is False + + +def test_nonnegative(): + assert ask(Q.nonnegative(-1)) is False + assert ask(Q.nonnegative(0)) + assert ask(Q.nonnegative(1)) + assert ask(~Q.negative(x), Q.nonnegative(x)) + assert ask(Q.nonnegative(x), Q.negative(x)) is False + assert ask(Q.nonnegative(sqrt(-1))) is False + assert ask(Q.nonnegative(x), Q.imaginary(x)) is False + +def test_real_basic(): + assert ask(Q.real(x)) is None + assert ask(Q.real(x), Q.real(x)) is True + assert ask(Q.real(x), Q.nonzero(x)) is True + assert ask(Q.real(x), Q.positive(x)) is True + assert ask(Q.real(x), Q.negative(x)) is True + assert ask(Q.real(x), Q.integer(x)) is True + assert ask(Q.real(x), Q.even(x)) is True + assert ask(Q.real(x), Q.prime(x)) is True + + assert ask(Q.real(x/sqrt(2)), Q.real(x)) is True + assert ask(Q.real(x/sqrt(-2)), Q.real(x)) is False + + assert ask(Q.real(x + 1), Q.real(x)) is True + assert ask(Q.real(x + I), Q.real(x)) is False + assert ask(Q.real(x + I), Q.complex(x)) is None + + assert ask(Q.real(2*x), Q.real(x)) is True + assert ask(Q.real(I*x), Q.real(x)) is False + assert ask(Q.real(I*x), Q.imaginary(x)) is True + assert ask(Q.real(I*x), Q.complex(x)) is None + + +def test_real_pow(): + assert ask(Q.real(x**2), Q.real(x)) is True + assert ask(Q.real(sqrt(x)), Q.negative(x)) is False + assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.real(y)) is None + assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True + assert ask(Q.real(x**y), Q.imaginary(x) & Q.imaginary(y)) is None # I**I or (2*I)**I + assert ask(Q.real(x**y), Q.imaginary(x) & Q.real(y)) is None # I**1 or I**0 + assert ask(Q.real(x**y), Q.real(x) & Q.imaginary(y)) is None # could be exp(2*pi*I) or 2**I + assert ask(Q.real(x**0), Q.imaginary(x)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True + assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True + assert ask(Q.real(x**y), Q.real(x) & Q.rational(y)) is None + assert ask(Q.real(x**y), Q.imaginary(x) & Q.integer(y)) is None + assert ask(Q.real(x**y), Q.imaginary(x) & Q.odd(y)) is False + assert ask(Q.real(x**y), Q.imaginary(x) & Q.even(y)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.rational(y/z) & Q.even(z) & Q.positive(x)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.rational(y/z) & Q.even(z) & Q.negative(x)) is False + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.integer(y/z)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.positive(x)) is True + assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.negative(x)) is False + assert ask(Q.real((-I)**i), Q.imaginary(i)) is True + assert ask(Q.real(I**i), Q.imaginary(i)) is True + assert ask(Q.real(i**i), Q.imaginary(i)) is None # i might be 2*I + assert ask(Q.real(x**i), Q.imaginary(i)) is None # x could be 0 + assert ask(Q.real(x**(I*pi/log(x))), Q.real(x)) is True + + +@_both_exp_pow +def test_real_functions(): + # trigonometric functions + assert ask(Q.real(sin(x))) is None + assert ask(Q.real(cos(x))) is None + assert ask(Q.real(sin(x)), Q.real(x)) is True + assert ask(Q.real(cos(x)), Q.real(x)) is True + + # exponential function + assert ask(Q.real(exp(x))) is None + assert ask(Q.real(exp(x)), Q.real(x)) is True + assert ask(Q.real(x + exp(x)), Q.real(x)) is True + assert ask(Q.real(exp(2*pi*I, evaluate=False))) is True + assert ask(Q.real(exp(pi*I, evaluate=False))) is True + assert ask(Q.real(exp(pi*I/2, evaluate=False))) is False + + # logarithm + assert ask(Q.real(log(I))) is False + assert ask(Q.real(log(2*I))) is False + assert ask(Q.real(log(I + 1))) is False + assert ask(Q.real(log(x)), Q.complex(x)) is None + assert ask(Q.real(log(x)), Q.imaginary(x)) is False + assert ask(Q.real(log(exp(x))), Q.imaginary(x)) is None # exp(2*pi*I) is 1, log(exp(pi*I)) is pi*I (disregarding periodicity) + assert ask(Q.real(log(exp(x))), Q.complex(x)) is None + eq = Pow(exp(2*pi*I*x, evaluate=False), x, evaluate=False) + assert ask(Q.real(eq), Q.integer(x)) is True + assert ask(Q.real(exp(x)**x), Q.imaginary(x)) is True + assert ask(Q.real(exp(x)**x), Q.complex(x)) is None + + # Q.complexes + assert ask(Q.real(re(x))) is True + assert ask(Q.real(im(x))) is True + + +def test_matrix(): + + # hermitian + assert ask(Q.hermitian(Matrix([[2, 2 + I, 4], [2 - I, 3, I], [4, -I, 1]]))) == True + assert ask(Q.hermitian(Matrix([[2, 2 + I, 4], [2 + I, 3, I], [4, -I, 1]]))) == False + z = symbols('z', complex=True) + assert ask(Q.hermitian(Matrix([[2, 2 + I, z], [2 - I, 3, I], [4, -I, 1]]))) == None + assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))))) == True + assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, I, 0), (-5, 0, 11))))) == False + assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, z, 0), (-5, 0, 11))))) == None + + # antihermitian + A = Matrix([[0, -2 - I, 0], [2 - I, 0, -I], [0, -I, 0]]) + B = Matrix([[-I, 2 + I, 0], [-2 + I, 0, 2 + I], [0, -2 + I, -I]]) + assert ask(Q.antihermitian(A)) is True + assert ask(Q.antihermitian(B)) is True + assert ask(Q.antihermitian(A**2)) is False + C = (B**3) + C.simplify() + assert ask(Q.antihermitian(C)) is True + _A = Matrix([[0, -2 - I, 0], [z, 0, -I], [0, -I, 0]]) + assert ask(Q.antihermitian(_A)) is None + + +@_both_exp_pow +def test_algebraic(): + assert ask(Q.algebraic(x)) is None + + assert ask(Q.algebraic(I)) is True + assert ask(Q.algebraic(2*I)) is True + assert ask(Q.algebraic(I/3)) is True + + assert ask(Q.algebraic(sqrt(7))) is True + assert ask(Q.algebraic(2*sqrt(7))) is True + assert ask(Q.algebraic(sqrt(7)/3)) is True + + assert ask(Q.algebraic(I*sqrt(3))) is True + assert ask(Q.algebraic(sqrt(1 + I*sqrt(3)))) is True + + assert ask(Q.algebraic(1 + I*sqrt(3)**Rational(17, 31))) is True + assert ask(Q.algebraic(1 + I*sqrt(3)**(17/pi))) is False + + for f in [exp, sin, tan, asin, atan, cos]: + assert ask(Q.algebraic(f(7))) is False + assert ask(Q.algebraic(f(7, evaluate=False))) is False + assert ask(Q.algebraic(f(0, evaluate=False))) is True + assert ask(Q.algebraic(f(x)), Q.algebraic(x)) is None + assert ask(Q.algebraic(f(x)), Q.algebraic(x) & Q.nonzero(x)) is False + + for g in [log, acos]: + assert ask(Q.algebraic(g(7))) is False + assert ask(Q.algebraic(g(7, evaluate=False))) is False + assert ask(Q.algebraic(g(1, evaluate=False))) is True + assert ask(Q.algebraic(g(x)), Q.algebraic(x)) is None + assert ask(Q.algebraic(g(x)), Q.algebraic(x) & Q.nonzero(x - 1)) is False + + for h in [cot, acot]: + assert ask(Q.algebraic(h(7))) is False + assert ask(Q.algebraic(h(7, evaluate=False))) is False + assert ask(Q.algebraic(h(x)), Q.algebraic(x)) is False + + assert ask(Q.algebraic(sqrt(sin(7)))) is False + assert ask(Q.algebraic(sqrt(y + I*sqrt(7)))) is None + + assert ask(Q.algebraic(2.47)) is True + + assert ask(Q.algebraic(x), Q.transcendental(x)) is False + assert ask(Q.transcendental(x), Q.algebraic(x)) is False + + +def test_global(): + """Test ask with global assumptions""" + assert ask(Q.integer(x)) is None + global_assumptions.add(Q.integer(x)) + assert ask(Q.integer(x)) is True + global_assumptions.clear() + assert ask(Q.integer(x)) is None + + +def test_custom_context(): + """Test ask with custom assumptions context""" + assert ask(Q.integer(x)) is None + local_context = AssumptionsContext() + local_context.add(Q.integer(x)) + assert ask(Q.integer(x), context=local_context) is True + assert ask(Q.integer(x)) is None + + +def test_functions_in_assumptions(): + assert ask(Q.negative(x), Q.real(x) >> Q.positive(x)) is False + assert ask(Q.negative(x), Equivalent(Q.real(x), Q.positive(x))) is False + assert ask(Q.negative(x), Xor(Q.real(x), Q.negative(x))) is False + + +def test_composite_ask(): + assert ask(Q.negative(x) & Q.integer(x), + assumptions=Q.real(x) >> Q.positive(x)) is False + + +def test_composite_proposition(): + assert ask(True) is True + assert ask(False) is False + assert ask(~Q.negative(x), Q.positive(x)) is True + assert ask(~Q.real(x), Q.commutative(x)) is None + assert ask(Q.negative(x) & Q.integer(x), Q.positive(x)) is False + assert ask(Q.negative(x) & Q.integer(x)) is None + assert ask(Q.real(x) | Q.integer(x), Q.positive(x)) is True + assert ask(Q.real(x) | Q.integer(x)) is None + assert ask(Q.real(x) >> Q.positive(x), Q.negative(x)) is False + assert ask(Implies( + Q.real(x), Q.positive(x), evaluate=False), Q.negative(x)) is False + assert ask(Implies(Q.real(x), Q.positive(x), evaluate=False)) is None + assert ask(Equivalent(Q.integer(x), Q.even(x)), Q.even(x)) is True + assert ask(Equivalent(Q.integer(x), Q.even(x))) is None + assert ask(Equivalent(Q.positive(x), Q.integer(x)), Q.integer(x)) is None + assert ask(Q.real(x) | Q.integer(x), Q.real(x) | Q.integer(x)) is True + +def test_tautology(): + assert ask(Q.real(x) | ~Q.real(x)) is True + assert ask(Q.real(x) & ~Q.real(x)) is False + +def test_composite_assumptions(): + assert ask(Q.real(x), Q.real(x) & Q.real(y)) is True + assert ask(Q.positive(x), Q.positive(x) | Q.positive(y)) is None + assert ask(Q.positive(x), Q.real(x) >> Q.positive(y)) is None + assert ask(Q.real(x), ~(Q.real(x) >> Q.real(y))) is True + +def test_key_extensibility(): + """test that you can add keys to the ask system at runtime""" + # make sure the key is not defined + raises(AttributeError, lambda: ask(Q.my_key(x))) + + # Old handler system + class MyAskHandler(AskHandler): + @staticmethod + def Symbol(expr, assumptions): + return True + try: + with warns_deprecated_sympy(): + register_handler('my_key', MyAskHandler) + with warns_deprecated_sympy(): + assert ask(Q.my_key(x)) is True + with warns_deprecated_sympy(): + assert ask(Q.my_key(x + 1)) is None + finally: + # We have to disable the stacklevel testing here because this raises + # the warning twice from two different places + with warns_deprecated_sympy(): + remove_handler('my_key', MyAskHandler) + del Q.my_key + raises(AttributeError, lambda: ask(Q.my_key(x))) + + # New handler system + class MyPredicate(Predicate): + pass + try: + Q.my_key = MyPredicate() + @Q.my_key.register(Symbol) + def _(expr, assumptions): + return True + assert ask(Q.my_key(x)) is True + assert ask(Q.my_key(x+1)) is None + finally: + del Q.my_key + raises(AttributeError, lambda: ask(Q.my_key(x))) + + +def test_type_extensibility(): + """test that new types can be added to the ask system at runtime + """ + from sympy.core import Basic + + class MyType(Basic): + pass + + @Q.prime.register(MyType) + def _(expr, assumptions): + return True + + assert ask(Q.prime(MyType())) is True + + +def test_single_fact_lookup(): + known_facts = And(Implies(Q.integer, Q.rational), + Implies(Q.rational, Q.real), + Implies(Q.real, Q.complex)) + known_facts_keys = {Q.integer, Q.rational, Q.real, Q.complex} + + known_facts_cnf = to_cnf(known_facts) + mapping = single_fact_lookup(known_facts_keys, known_facts_cnf) + + assert mapping[Q.rational] == {Q.real, Q.rational, Q.complex} + + +def test_generate_known_facts_dict(): + known_facts = And(Implies(Q.integer(x), Q.rational(x)), + Implies(Q.rational(x), Q.real(x)), + Implies(Q.real(x), Q.complex(x))) + known_facts_keys = {Q.integer(x), Q.rational(x), Q.real(x), Q.complex(x)} + + assert generate_known_facts_dict(known_facts_keys, known_facts) == \ + {Q.complex: ({Q.complex}, set()), + Q.integer: ({Q.complex, Q.integer, Q.rational, Q.real}, set()), + Q.rational: ({Q.complex, Q.rational, Q.real}, set()), + Q.real: ({Q.complex, Q.real}, set())} + + +@slow +def test_known_facts_consistent(): + """"Test that ask_generated.py is up-to-date""" + x = Symbol('x') + fact = get_known_facts(x) + # test cnf clauses of fact between unary predicates + cnf = CNF.to_CNF(fact) + clauses = set() + clauses.update(frozenset(Literal(lit.arg.function, lit.is_Not) for lit in sorted(cl, key=str)) for cl in cnf.clauses) + assert get_all_known_facts() == clauses + # test dictionary of fact between unary predicates + keys = [pred(x) for pred in get_known_facts_keys()] + mapping = generate_known_facts_dict(keys, fact) + assert get_known_facts_dict() == mapping + + +def test_Add_queries(): + assert ask(Q.prime(12345678901234567890 + (cos(1)**2 + sin(1)**2))) is True + assert ask(Q.even(Add(S(2), S(2), evaluate=0))) is True + assert ask(Q.prime(Add(S(2), S(2), evaluate=0))) is False + assert ask(Q.integer(Add(S(2), S(2), evaluate=0))) is True + + +def test_positive_assuming(): + with assuming(Q.positive(x + 1)): + assert not ask(Q.positive(x)) + + +def test_issue_5421(): + raises(TypeError, lambda: ask(pi/log(x), Q.real)) + + +def test_issue_3906(): + raises(TypeError, lambda: ask(Q.positive)) + + +def test_issue_5833(): + assert ask(Q.positive(log(x)**2), Q.positive(x)) is None + assert ask(~Q.negative(log(x)**2), Q.positive(x)) is True + + +def test_issue_6732(): + raises(ValueError, lambda: ask(Q.positive(x), Q.positive(x) & Q.negative(x))) + raises(ValueError, lambda: ask(Q.negative(x), Q.positive(x) & Q.negative(x))) + + +def test_issue_7246(): + assert ask(Q.positive(atan(p)), Q.positive(p)) is True + assert ask(Q.positive(atan(p)), Q.negative(p)) is False + assert ask(Q.positive(atan(p)), Q.zero(p)) is False + assert ask(Q.positive(atan(x))) is None + + assert ask(Q.positive(asin(p)), Q.positive(p)) is None + assert ask(Q.positive(asin(p)), Q.zero(p)) is None + assert ask(Q.positive(asin(Rational(1, 7)))) is True + assert ask(Q.positive(asin(x)), Q.positive(x) & Q.nonpositive(x - 1)) is True + assert ask(Q.positive(asin(x)), Q.negative(x) & Q.nonnegative(x + 1)) is False + + assert ask(Q.positive(acos(p)), Q.positive(p)) is None + assert ask(Q.positive(acos(Rational(1, 7)))) is True + assert ask(Q.positive(acos(x)), Q.nonnegative(x + 1) & Q.nonpositive(x - 1)) is True + assert ask(Q.positive(acos(x)), Q.nonnegative(x - 1)) is None + + assert ask(Q.positive(acot(x)), Q.positive(x)) is True + assert ask(Q.positive(acot(x)), Q.real(x)) is True + assert ask(Q.positive(acot(x)), Q.imaginary(x)) is False + assert ask(Q.positive(acot(x))) is None + + +@XFAIL +def test_issue_7246_failing(): + #Move this test to test_issue_7246 once + #the new assumptions module is improved. + assert ask(Q.positive(acos(x)), Q.zero(x)) is True + + +def test_check_old_assumption(): + x = symbols('x', real=True) + assert ask(Q.real(x)) is True + assert ask(Q.imaginary(x)) is False + assert ask(Q.complex(x)) is True + + x = symbols('x', imaginary=True) + assert ask(Q.real(x)) is False + assert ask(Q.imaginary(x)) is True + assert ask(Q.complex(x)) is True + + x = symbols('x', complex=True) + assert ask(Q.real(x)) is None + assert ask(Q.complex(x)) is True + + x = symbols('x', positive=True) + assert ask(Q.positive(x)) is True + assert ask(Q.negative(x)) is False + assert ask(Q.real(x)) is True + + x = symbols('x', commutative=False) + assert ask(Q.commutative(x)) is False + + x = symbols('x', negative=True) + assert ask(Q.positive(x)) is False + assert ask(Q.negative(x)) is True + + x = symbols('x', nonnegative=True) + assert ask(Q.negative(x)) is False + assert ask(Q.positive(x)) is None + assert ask(Q.zero(x)) is None + + x = symbols('x', finite=True) + assert ask(Q.finite(x)) is True + + x = symbols('x', prime=True) + assert ask(Q.prime(x)) is True + assert ask(Q.composite(x)) is False + + x = symbols('x', composite=True) + assert ask(Q.prime(x)) is False + assert ask(Q.composite(x)) is True + + x = symbols('x', even=True) + assert ask(Q.even(x)) is True + assert ask(Q.odd(x)) is False + + x = symbols('x', odd=True) + assert ask(Q.even(x)) is False + assert ask(Q.odd(x)) is True + + x = symbols('x', nonzero=True) + assert ask(Q.nonzero(x)) is True + assert ask(Q.zero(x)) is False + + x = symbols('x', zero=True) + assert ask(Q.zero(x)) is True + + x = symbols('x', integer=True) + assert ask(Q.integer(x)) is True + + x = symbols('x', rational=True) + assert ask(Q.rational(x)) is True + assert ask(Q.irrational(x)) is False + + x = symbols('x', irrational=True) + assert ask(Q.irrational(x)) is True + assert ask(Q.rational(x)) is False + + +def test_issue_9636(): + assert ask(Q.integer(1.0)) is None + assert ask(Q.prime(3.0)) is None + assert ask(Q.composite(4.0)) is None + assert ask(Q.even(2.0)) is None + assert ask(Q.odd(3.0)) is None + + +def test_autosimp_used_to_fail(): + # See issue #9807 + assert ask(Q.imaginary(0**I)) is None + assert ask(Q.imaginary(0**(-I))) is None + assert ask(Q.real(0**I)) is None + assert ask(Q.real(0**(-I))) is None + + +def test_custom_AskHandler(): + from sympy.logic.boolalg import conjuncts + + # Old handler system + class MersenneHandler(AskHandler): + @staticmethod + def Integer(expr, assumptions): + if ask(Q.integer(log(expr + 1, 2))): + return True + @staticmethod + def Symbol(expr, assumptions): + if expr in conjuncts(assumptions): + return True + try: + with warns_deprecated_sympy(): + register_handler('mersenne', MersenneHandler) + n = Symbol('n', integer=True) + with warns_deprecated_sympy(): + assert ask(Q.mersenne(7)) + with warns_deprecated_sympy(): + assert ask(Q.mersenne(n), Q.mersenne(n)) + finally: + del Q.mersenne + + # New handler system + class MersennePredicate(Predicate): + pass + try: + Q.mersenne = MersennePredicate() + @Q.mersenne.register(Integer) + def _(expr, assumptions): + if ask(Q.integer(log(expr + 1, 2))): + return True + @Q.mersenne.register(Symbol) + def _(expr, assumptions): + if expr in conjuncts(assumptions): + return True + assert ask(Q.mersenne(7)) + assert ask(Q.mersenne(n), Q.mersenne(n)) + finally: + del Q.mersenne + + +def test_polyadic_predicate(): + + class SexyPredicate(Predicate): + pass + try: + Q.sexyprime = SexyPredicate() + + @Q.sexyprime.register(Integer, Integer) + def _(int1, int2, assumptions): + args = sorted([int1, int2]) + if not all(ask(Q.prime(a), assumptions) for a in args): + return False + return args[1] - args[0] == 6 + + @Q.sexyprime.register(Integer, Integer, Integer) + def _(int1, int2, int3, assumptions): + args = sorted([int1, int2, int3]) + if not all(ask(Q.prime(a), assumptions) for a in args): + return False + return args[2] - args[1] == 6 and args[1] - args[0] == 6 + + assert ask(Q.sexyprime(5, 11)) + assert ask(Q.sexyprime(7, 13, 19)) + finally: + del Q.sexyprime + + +def test_Predicate_handler_is_unique(): + + # Undefined predicate does not have a handler + assert Predicate('mypredicate').handler is None + + # Handler of defined predicate is unique to the class + class MyPredicate(Predicate): + pass + mp1 = MyPredicate(Str('mp1')) + mp2 = MyPredicate(Str('mp2')) + assert mp1.handler is mp2.handler + + +def test_relational(): + assert ask(Q.eq(x, 0), Q.zero(x)) + assert not ask(Q.eq(x, 0), Q.nonzero(x)) + assert not ask(Q.ne(x, 0), Q.zero(x)) + assert ask(Q.ne(x, 0), Q.nonzero(x)) + + +def test_issue_25221(): + assert ask(Q.transcendental(x), Q.algebraic(x) | Q.positive(y,y)) is None + assert ask(Q.transcendental(x), Q.algebraic(x) | (0 > y)) is None + assert ask(Q.transcendental(x), Q.algebraic(x) | Q.gt(0,y)) is None diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_refine.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_refine.py new file mode 100644 index 0000000000000000000000000000000000000000..81533a88b232cd5c3cfb9be17d09dad404d679dc --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_refine.py @@ -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] diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_rel_queries.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_rel_queries.py new file mode 100644 index 0000000000000000000000000000000000000000..6f7d50b7f9bb5674d699cef0358f2366a0bd0f48 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_rel_queries.py @@ -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 symetry 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 diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_satask.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_satask.py new file mode 100644 index 0000000000000000000000000000000000000000..5831b69e3e6bf2b1a906d1140967510c2ea8b630 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_satask.py @@ -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)})} diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_sathandlers.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_sathandlers.py new file mode 100644 index 0000000000000000000000000000000000000000..9d568ad8efe6ba7cf7f5eb03879ad6764c16e729 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_sathandlers.py @@ -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))) diff --git a/lib/python3.12/site-packages/sympy/assumptions/tests/test_wrapper.py b/lib/python3.12/site-packages/sympy/assumptions/tests/test_wrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..af9afd5d51fb1341e0b08149dc842b78a39c329b --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/tests/test_wrapper.py @@ -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)) diff --git a/lib/python3.12/site-packages/sympy/assumptions/wrapper.py b/lib/python3.12/site-packages/sympy/assumptions/wrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..cb06e9de770ed41a2b3d6fe63381ad1cb59acacc --- /dev/null +++ b/lib/python3.12/site-packages/sympy/assumptions/wrapper.py @@ -0,0 +1,164 @@ +""" +Functions and wrapper object to call assumption property and predicate +query with same syntax. + +In SymPy, there are two assumption systems. Old assumption system is +defined in sympy/core/assumptions, and it can be accessed by attribute +such as ``x.is_even``. New assumption system is defined in +sympy/assumptions, and it can be accessed by predicates such as +``Q.even(x)``. + +Old assumption is fast, while new assumptions can freely take local facts. +In general, old assumption is used in evaluation method and new assumption +is used in refinement method. + +In most cases, both evaluation and refinement follow the same process, and +the only difference is which assumption system is used. This module provides +``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows +using two systems with same syntax so that parallel code implementation can be +avoided. + +Examples +======== + +For multiple use, use ``AssumptionsWrapper()``. + +>>> from sympy import Q, Symbol +>>> from sympy.assumptions.wrapper import AssumptionsWrapper +>>> x = Symbol('x') +>>> _x = AssumptionsWrapper(x, Q.even(x)) +>>> _x.is_integer +True +>>> _x.is_odd +False + +For single use, use ``is_[...]()`` functions. + +>>> from sympy.assumptions.wrapper import is_infinite +>>> a = Symbol('a') +>>> print(is_infinite(a)) +None +>>> is_infinite(a, Q.finite(a)) +False + +""" + +from sympy.assumptions import ask, Q +from sympy.core.basic import Basic +from sympy.core.sympify import _sympify + + +def make_eval_method(fact): + def getit(self): + pred = getattr(Q, fact) + ret = ask(pred(self.expr), self.assumptions) + return ret + return getit + + +# we subclass Basic to use the fact deduction and caching +class AssumptionsWrapper(Basic): + """ + Wrapper over ``Basic`` instances to call predicate query by + ``.is_[...]`` property + + Parameters + ========== + + expr : Basic + + assumptions : Boolean, optional + + Examples + ======== + + >>> from sympy import Q, Symbol + >>> from sympy.assumptions.wrapper import AssumptionsWrapper + >>> x = Symbol('x', even=True) + >>> AssumptionsWrapper(x).is_integer + True + >>> y = Symbol('y') + >>> AssumptionsWrapper(y, Q.even(y)).is_integer + True + + With ``AssumptionsWrapper``, both evaluation and refinement can be supported + by single implementation. + + >>> from sympy import Function + >>> class MyAbs(Function): + ... @classmethod + ... def eval(cls, x, assumptions=True): + ... _x = AssumptionsWrapper(x, assumptions) + ... if _x.is_nonnegative: + ... return x + ... if _x.is_negative: + ... return -x + ... def _eval_refine(self, assumptions): + ... return MyAbs.eval(self.args[0], assumptions) + >>> MyAbs(x) + MyAbs(x) + >>> MyAbs(x).refine(Q.positive(x)) + x + >>> MyAbs(Symbol('y', negative=True)) + -y + + """ + def __new__(cls, expr, assumptions=None): + if assumptions is None: + return expr + obj = super().__new__(cls, expr, _sympify(assumptions)) + obj.expr = expr + obj.assumptions = assumptions + return obj + + _eval_is_algebraic = make_eval_method("algebraic") + _eval_is_antihermitian = make_eval_method("antihermitian") + _eval_is_commutative = make_eval_method("commutative") + _eval_is_complex = make_eval_method("complex") + _eval_is_composite = make_eval_method("composite") + _eval_is_even = make_eval_method("even") + _eval_is_extended_negative = make_eval_method("extended_negative") + _eval_is_extended_nonnegative = make_eval_method("extended_nonnegative") + _eval_is_extended_nonpositive = make_eval_method("extended_nonpositive") + _eval_is_extended_nonzero = make_eval_method("extended_nonzero") + _eval_is_extended_positive = make_eval_method("extended_positive") + _eval_is_extended_real = make_eval_method("extended_real") + _eval_is_finite = make_eval_method("finite") + _eval_is_hermitian = make_eval_method("hermitian") + _eval_is_imaginary = make_eval_method("imaginary") + _eval_is_infinite = make_eval_method("infinite") + _eval_is_integer = make_eval_method("integer") + _eval_is_irrational = make_eval_method("irrational") + _eval_is_negative = make_eval_method("negative") + _eval_is_noninteger = make_eval_method("noninteger") + _eval_is_nonnegative = make_eval_method("nonnegative") + _eval_is_nonpositive = make_eval_method("nonpositive") + _eval_is_nonzero = make_eval_method("nonzero") + _eval_is_odd = make_eval_method("odd") + _eval_is_polar = make_eval_method("polar") + _eval_is_positive = make_eval_method("positive") + _eval_is_prime = make_eval_method("prime") + _eval_is_rational = make_eval_method("rational") + _eval_is_real = make_eval_method("real") + _eval_is_transcendental = make_eval_method("transcendental") + _eval_is_zero = make_eval_method("zero") + + +# one shot functions which are faster than AssumptionsWrapper + +def is_infinite(obj, assumptions=None): + if assumptions is None: + return obj.is_infinite + return ask(Q.infinite(obj), assumptions) + + +def is_extended_real(obj, assumptions=None): + if assumptions is None: + return obj.is_extended_real + return ask(Q.extended_real(obj), assumptions) + + +def is_extended_nonnegative(obj, assumptions=None): + if assumptions is None: + return obj.is_extended_nonnegative + return ask(Q.extended_nonnegative(obj), assumptions) diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c8fcc47de4aa68fdd1fd4ae544e8af386eb53af Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/bbp_pi.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/bbp_pi.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75a1b67cbe1cd5729ffb05a2ebcb753acfb01a52 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/bbp_pi.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/continued_fraction.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/continued_fraction.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..698291a408859adcde867806a76f8d610fcabfcb Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/continued_fraction.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/digits.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/digits.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f35bac0df8e0ecb0c6f471dc8446cabebdcb1f98 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/digits.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/ecm.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/ecm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d14e7da014f1faac00dd9472c2c53c628f1d6577 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/ecm.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/egyptian_fraction.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/egyptian_fraction.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbfef45d25178f3aab2605f90476b7c3ad3e919f Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/egyptian_fraction.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/elliptic_curve.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/elliptic_curve.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..146697ea26e7f3d7350df8392c6d5f6a184cde7c Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/elliptic_curve.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/factor_.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/factor_.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a661bbe599478e718b459f15902c16fb3d44c5ec Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/factor_.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/generate.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/generate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6b435132ea7781ae1da133f605f7979e64585da Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/generate.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/modular.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/modular.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87d3b3baa4596de6c8455324b8d553c33bd8c322 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/modular.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/multinomial.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/multinomial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6048d7cde600a80b6d2ace64b78a61abb96015a Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/multinomial.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/partitions_.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/partitions_.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac7315797998771671c578859338348f8580d1d2 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/partitions_.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/primetest.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/primetest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea5ad4b688f87276a0d5336c3ed0aa4ffd1388ef Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/primetest.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/qs.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/qs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e4cb819b163cbb6d49f39e5abadf43342fef6bc Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/qs.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/__pycache__/residue_ntheory.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/residue_ntheory.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e8c39db930d9ca224ad47e6cab7f2db8ee844b3 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/__pycache__/residue_ntheory.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99908f59f629da39af02b70930f458fc9da309b1 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_digits.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_digits.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d98d233838f54b393b599adae82b7eff679ad68 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_digits.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_egyptian_fraction.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_egyptian_fraction.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34886679f3d1f8d62f3c3f5fa04e1e1c0384feac Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_egyptian_fraction.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_elliptic_curve.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_elliptic_curve.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41dbdacdef36f955d93dcccdf0a4869f0d2745de Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_elliptic_curve.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_generate.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_generate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef5e650bfbcf5fe2e58922409e31c2a7bd9f4a09 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_generate.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_modular.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_modular.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f2cea11688fd37f348002b6b6181dfb9977c7bf Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_modular.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_multinomial.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_multinomial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e9e2574825a85ed8f293760e2fea6f7f477ceb8 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_multinomial.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_partitions.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_partitions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ae79d8cd2780e0fcbefd7a84783cf9ea2648d3d Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_partitions.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_primetest.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_primetest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa69141f10d53398d0a168fe938df76108591296 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_primetest.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_residue.cpython-312.pyc b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_residue.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c12d8947338f25931479f1e129ebe1a947f4269 Binary files /dev/null and b/lib/python3.12/site-packages/sympy/ntheory/tests/__pycache__/test_residue.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_ast_parser.cpython-312.pyc b/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_ast_parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e90c5e468ed1d5de94bdf1b6d3f85a7b77e48e0d Binary files /dev/null and b/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_ast_parser.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_mathematica.cpython-312.pyc b/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_mathematica.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff3eefd872b85b0e30a3669ed27e3188a7457afd Binary files /dev/null and b/lib/python3.12/site-packages/sympy/parsing/tests/__pycache__/test_mathematica.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_c_parser.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_c_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..b74622e40030cba180cb4fc354216ccca119baec --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_c_parser.py @@ -0,0 +1,5248 @@ +from sympy.parsing.sym_expr import SymPyExpression +from sympy.testing.pytest import raises, XFAIL +from sympy.external import import_module + +cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) + +if cin: + from sympy.codegen.ast import (Variable, String, Return, + FunctionDefinition, Integer, Float, Declaration, CodeBlock, + FunctionPrototype, FunctionCall, NoneToken, Assignment, Type, + IntBaseType, SignedIntType, UnsignedIntType, FloatType, + AddAugmentedAssignment, SubAugmentedAssignment, + MulAugmentedAssignment, DivAugmentedAssignment, + ModAugmentedAssignment, While) + from sympy.codegen.cnodes import (PreDecrement, PostDecrement, + PreIncrement, PostIncrement) + from sympy.core import (Add, Mul, Mod, Pow, Rational, + StrictLessThan, LessThan, StrictGreaterThan, GreaterThan, + Equality, Unequality) + from sympy.logic.boolalg import And, Not, Or + from sympy.core.symbol import Symbol + from sympy.logic.boolalg import (false, true) + import os + + def test_variable(): + c_src1 = ( + 'int a;' + '\n' + + 'int b;' + '\n' + ) + c_src2 = ( + 'float a;' + '\n' + + 'float b;' + '\n' + ) + c_src3 = ( + 'int a;' + '\n' + + 'float b;' + '\n' + + 'int c;' + ) + c_src4 = ( + 'int x = 1, y = 6.78;' + '\n' + + 'float p = 2, q = 9.67;' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + + assert res1[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + + assert res1[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')) + ) + ) + + assert res2[0] == Declaration( + Variable( + Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ) + assert res2[1] == Declaration( + Variable( + Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ) + + assert res3[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + + assert res3[1] == Declaration( + Variable( + Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ) + + assert res3[2] == Declaration( + Variable( + Symbol('c'), + type=IntBaseType(String('intc')) + ) + ) + + assert res4[0] == Declaration( + Variable( + Symbol('x'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res4[1] == Declaration( + Variable( + Symbol('y'), + type=IntBaseType(String('intc')), + value=Integer(6) + ) + ) + + assert res4[2] == Declaration( + Variable( + Symbol('p'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.0', precision=53) + ) + ) + + assert res4[3] == Declaration( + Variable( + Symbol('q'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('9.67', precision=53) + ) + ) + + + def test_int(): + c_src1 = 'int a = 1;' + c_src2 = ( + 'int a = 1;' + '\n' + + 'int b = 2;' + '\n' + ) + c_src3 = 'int a = 2.345, b = 5.67;' + c_src4 = 'int p = 6, q = 23.45;' + c_src5 = "int x = '0', y = 'a';" + c_src6 = "int r = true, s = false;" + + # cin.TypeKind.UCHAR + c_src_type1 = ( + "signed char a = 1, b = 5.1;" + ) + + # cin.TypeKind.SHORT + c_src_type2 = ( + "short a = 1, b = 5.1;" + "signed short c = 1, d = 5.1;" + "short int e = 1, f = 5.1;" + "signed short int g = 1, h = 5.1;" + ) + + # cin.TypeKind.INT + c_src_type3 = ( + "signed int a = 1, b = 5.1;" + "int c = 1, d = 5.1;" + ) + + # cin.TypeKind.LONG + c_src_type4 = ( + "long a = 1, b = 5.1;" + "long int c = 1, d = 5.1;" + ) + + # cin.TypeKind.UCHAR + c_src_type5 = "unsigned char a = 1, b = 5.1;" + + # cin.TypeKind.USHORT + c_src_type6 = ( + "unsigned short a = 1, b = 5.1;" + "unsigned short int c = 1, d = 5.1;" + ) + + # cin.TypeKind.UINT + c_src_type7 = "unsigned int a = 1, b = 5.1;" + + # cin.TypeKind.ULONG + c_src_type8 = ( + "unsigned long a = 1, b = 5.1;" + "unsigned long int c = 1, d = 5.1;" + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + res6 = SymPyExpression(c_src6, 'c').return_expr() + + res_type1 = SymPyExpression(c_src_type1, 'c').return_expr() + res_type2 = SymPyExpression(c_src_type2, 'c').return_expr() + res_type3 = SymPyExpression(c_src_type3, 'c').return_expr() + res_type4 = SymPyExpression(c_src_type4, 'c').return_expr() + res_type5 = SymPyExpression(c_src_type5, 'c').return_expr() + res_type6 = SymPyExpression(c_src_type6, 'c').return_expr() + res_type7 = SymPyExpression(c_src_type7, 'c').return_expr() + res_type8 = SymPyExpression(c_src_type8, 'c').return_expr() + + assert res1[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res2[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res2[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res3[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res3[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(5) + ) + ) + + assert res4[0] == Declaration( + Variable( + Symbol('p'), + type=IntBaseType(String('intc')), + value=Integer(6) + ) + ) + + assert res4[1] == Declaration( + Variable( + Symbol('q'), + type=IntBaseType(String('intc')), + value=Integer(23) + ) + ) + + assert res5[0] == Declaration( + Variable( + Symbol('x'), + type=IntBaseType(String('intc')), + value=Integer(48) + ) + ) + + assert res5[1] == Declaration( + Variable( + Symbol('y'), + type=IntBaseType(String('intc')), + value=Integer(97) + ) + ) + + assert res6[0] == Declaration( + Variable( + Symbol('r'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res6[1] == Declaration( + Variable( + Symbol('s'), + type=IntBaseType(String('intc')), + value=Integer(0) + ) + ) + + assert res_type1[0] == Declaration( + Variable( + Symbol('a'), + type=SignedIntType( + String('int8'), + nbits=Integer(8) + ), + value=Integer(1) + ) + ) + + assert res_type1[1] == Declaration( + Variable( + Symbol('b'), + type=SignedIntType( + String('int8'), + nbits=Integer(8) + ), + value=Integer(5) + ) + ) + + assert res_type2[0] == Declaration( + Variable( + Symbol('a'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type2[1] == Declaration( + Variable( + Symbol('b'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type2[2] == Declaration( + Variable(Symbol('c'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type2[3] == Declaration( + Variable( + Symbol('d'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type2[4] == Declaration( + Variable( + Symbol('e'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type2[5] == Declaration( + Variable( + Symbol('f'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type2[6] == Declaration( + Variable( + Symbol('g'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type2[7] == Declaration( + Variable( + Symbol('h'), + type=SignedIntType( + String('int16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type3[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res_type3[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(5) + ) + ) + + assert res_type3[2] == Declaration( + Variable( + Symbol('c'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res_type3[3] == Declaration( + Variable( + Symbol('d'), + type=IntBaseType(String('intc')), + value=Integer(5) + ) + ) + + assert res_type4[0] == Declaration( + Variable( + Symbol('a'), + type=SignedIntType( + String('int64'), + nbits=Integer(64) + ), + value=Integer(1) + ) + ) + + assert res_type4[1] == Declaration( + Variable( + Symbol('b'), + type=SignedIntType( + String('int64'), + nbits=Integer(64) + ), + value=Integer(5) + ) + ) + + assert res_type4[2] == Declaration( + Variable( + Symbol('c'), + type=SignedIntType( + String('int64'), + nbits=Integer(64) + ), + value=Integer(1) + ) + ) + + assert res_type4[3] == Declaration( + Variable( + Symbol('d'), + type=SignedIntType( + String('int64'), + nbits=Integer(64) + ), + value=Integer(5) + ) + ) + + assert res_type5[0] == Declaration( + Variable( + Symbol('a'), + type=UnsignedIntType( + String('uint8'), + nbits=Integer(8) + ), + value=Integer(1) + ) + ) + + assert res_type5[1] == Declaration( + Variable( + Symbol('b'), + type=UnsignedIntType( + String('uint8'), + nbits=Integer(8) + ), + value=Integer(5) + ) + ) + + assert res_type6[0] == Declaration( + Variable( + Symbol('a'), + type=UnsignedIntType( + String('uint16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type6[1] == Declaration( + Variable( + Symbol('b'), + type=UnsignedIntType( + String('uint16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type6[2] == Declaration( + Variable( + Symbol('c'), + type=UnsignedIntType( + String('uint16'), + nbits=Integer(16) + ), + value=Integer(1) + ) + ) + + assert res_type6[3] == Declaration( + Variable( + Symbol('d'), + type=UnsignedIntType( + String('uint16'), + nbits=Integer(16) + ), + value=Integer(5) + ) + ) + + assert res_type7[0] == Declaration( + Variable( + Symbol('a'), + type=UnsignedIntType( + String('uint32'), + nbits=Integer(32) + ), + value=Integer(1) + ) + ) + + assert res_type7[1] == Declaration( + Variable( + Symbol('b'), + type=UnsignedIntType( + String('uint32'), + nbits=Integer(32) + ), + value=Integer(5) + ) + ) + + assert res_type8[0] == Declaration( + Variable( + Symbol('a'), + type=UnsignedIntType( + String('uint64'), + nbits=Integer(64) + ), + value=Integer(1) + ) + ) + + assert res_type8[1] == Declaration( + Variable( + Symbol('b'), + type=UnsignedIntType( + String('uint64'), + nbits=Integer(64) + ), + value=Integer(5) + ) + ) + + assert res_type8[2] == Declaration( + Variable( + Symbol('c'), + type=UnsignedIntType( + String('uint64'), + nbits=Integer(64) + ), + value=Integer(1) + ) + ) + + assert res_type8[3] == Declaration( + Variable( + Symbol('d'), + type=UnsignedIntType( + String('uint64'), + nbits=Integer(64) + ), + value=Integer(5) + ) + ) + + + def test_float(): + c_src1 = 'float a = 1.0;' + c_src2 = ( + 'float a = 1.25;' + '\n' + + 'float b = 2.39;' + '\n' + ) + c_src3 = 'float x = 1, y = 2;' + c_src4 = 'float p = 5, e = 7.89;' + c_src5 = 'float r = true, s = false;' + + # cin.TypeKind.FLOAT + c_src_type1 = 'float x = 1, y = 2.5;' + + # cin.TypeKind.DOUBLE + c_src_type2 = 'double x = 1, y = 2.5;' + + # cin.TypeKind.LONGDOUBLE + c_src_type3 = 'long double x = 1, y = 2.5;' + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + + res_type1 = SymPyExpression(c_src_type1, 'c').return_expr() + res_type2 = SymPyExpression(c_src_type2, 'c').return_expr() + res_type3 = SymPyExpression(c_src_type3, 'c').return_expr() + + assert res1[0] == Declaration( + Variable( + Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res2[0] == Declaration( + Variable( + Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.25', precision=53) + ) + ) + + assert res2[1] == Declaration( + Variable( + Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.3900000000000001', precision=53) + ) + ) + + assert res3[0] == Declaration( + Variable( + Symbol('x'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res3[1] == Declaration( + Variable( + Symbol('y'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.0', precision=53) + ) + ) + + assert res4[0] == Declaration( + Variable( + Symbol('p'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('5.0', precision=53) + ) + ) + + assert res4[1] == Declaration( + Variable( + Symbol('e'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('7.89', precision=53) + ) + ) + + assert res5[0] == Declaration( + Variable( + Symbol('r'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res5[1] == Declaration( + Variable( + Symbol('s'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('0.0', precision=53) + ) + ) + + assert res_type1[0] == Declaration( + Variable( + Symbol('x'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res_type1[1] == Declaration( + Variable( + Symbol('y'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.5', precision=53) + ) + ) + assert res_type2[0] == Declaration( + Variable( + Symbol('x'), + type=FloatType( + String('float64'), + nbits=Integer(64), + nmant=Integer(52), + nexp=Integer(11) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res_type2[1] == Declaration( + Variable( + Symbol('y'), + type=FloatType( + String('float64'), + nbits=Integer(64), + nmant=Integer(52), + nexp=Integer(11) + ), + value=Float('2.5', precision=53) + ) + ) + + assert res_type3[0] == Declaration( + Variable( + Symbol('x'), + type=FloatType( + String('float80'), + nbits=Integer(80), + nmant=Integer(63), + nexp=Integer(15) + ), + value=Float('1.0', precision=53) + ) + ) + + assert res_type3[1] == Declaration( + Variable( + Symbol('y'), + type=FloatType( + String('float80'), + nbits=Integer(80), + nmant=Integer(63), + nexp=Integer(15) + ), + value=Float('2.5', precision=53) + ) + ) + + + def test_bool(): + c_src1 = ( + 'bool a = true, b = false;' + ) + + c_src2 = ( + 'bool a = 1, b = 0;' + ) + + c_src3 = ( + 'bool a = 10, b = 20;' + ) + + c_src4 = ( + 'bool a = 19.1, b = 9.0, c = 0.0;' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + + assert res1[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=true + ) + ) + + assert res1[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=false + ) + ) + + assert res2[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=true) + ) + + assert res2[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=false + ) + ) + + assert res3[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=true + ) + ) + + assert res3[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=true + ) + ) + + assert res4[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=true) + ) + + assert res4[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=true + ) + ) + + assert res4[2] == Declaration( + Variable(Symbol('c'), + type=Type(String('bool')), + value=false + ) + ) + + @XFAIL # this is expected to fail because of a bug in the C parser. + def test_function(): + c_src1 = ( + 'void fun1()' + '\n' + + '{' + '\n' + + 'int a;' + '\n' + + '}' + ) + c_src2 = ( + 'int fun2()' + '\n' + + '{'+ '\n' + + 'int a;' + '\n' + + 'return a;' + '\n' + + '}' + ) + c_src3 = ( + 'float fun3()' + '\n' + + '{' + '\n' + + 'float b;' + '\n' + + 'return b;' + '\n' + + '}' + ) + c_src4 = ( + 'float fun4()' + '\n' + + '{}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + + assert res1[0] == FunctionDefinition( + NoneToken(), + name=String('fun1'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + ) + ) + + assert res2[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun2'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Return('a') + ) + ) + + assert res3[0] == FunctionDefinition( + FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + name=String('fun3'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Return('b') + ) + ) + + assert res4[0] == FunctionPrototype( + FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + name=String('fun4'), + parameters=() + ) + + @XFAIL # this is expected to fail because of a bug in the C parser. + def test_parameters(): + c_src1 = ( + 'void fun1( int a)' + '\n' + + '{' + '\n' + + 'int i;' + '\n' + + '}' + ) + c_src2 = ( + 'int fun2(float x, float y)' + '\n' + + '{'+ '\n' + + 'int a;' + '\n' + + 'return a;' + '\n' + + '}' + ) + c_src3 = ( + 'float fun3(int p, float q, int r)' + '\n' + + '{' + '\n' + + 'float b;' + '\n' + + 'return b;' + '\n' + + '}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + + assert res1[0] == FunctionDefinition( + NoneToken(), + name=String('fun1'), + parameters=( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ), + ), + body=CodeBlock( + Declaration( + Variable( + Symbol('i'), + type=IntBaseType(String('intc')) + ) + ) + ) + ) + + assert res2[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun2'), + parameters=( + Variable( + Symbol('x'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ), + Variable( + Symbol('y'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + body=CodeBlock( + Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Return('a') + ) + ) + + assert res3[0] == FunctionDefinition( + FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + name=String('fun3'), + parameters=( + Variable( + Symbol('p'), + type=IntBaseType(String('intc')) + ), + Variable( + Symbol('q'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ), + Variable( + Symbol('r'), + type=IntBaseType(String('intc')) + ) + ), + body=CodeBlock( + Declaration( + Variable( + Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Return('b') + ) + ) + + @XFAIL # this is expected to fail because of a bug in the C parser. + def test_function_call(): + c_src1 = ( + 'int fun1(int x)' + '\n' + + '{' + '\n' + + 'return x;' + '\n' + + '}' + '\n' + + 'void caller()' + '\n' + + '{' + '\n' + + 'int x = fun1(2);' + '\n' + + '}' + ) + + c_src2 = ( + 'int fun2(int a, int b, int c)' + '\n' + + '{' + '\n' + + 'return a;' + '\n' + + '}' + '\n' + + 'void caller()' + '\n' + + '{' + '\n' + + 'int y = fun2(2, 3, 4);' + '\n' + + '}' + ) + + c_src3 = ( + 'int fun3(int a, int b, int c)' + '\n' + + '{' + '\n' + + 'return b;' + '\n' + + '}' + '\n' + + 'void caller()' + '\n' + + '{' + '\n' + + 'int p;' + '\n' + + 'int q;' + '\n' + + 'int r;' + '\n' + + 'int z = fun3(p, q, r);' + '\n' + + '}' + ) + + c_src4 = ( + 'int fun4(float a, float b, int c)' + '\n' + + '{' + '\n' + + 'return c;' + '\n' + + '}' + '\n' + + 'void caller()' + '\n' + + '{' + '\n' + + 'float x;' + '\n' + + 'float y;' + '\n' + + 'int z;' + '\n' + + 'int i = fun4(x, y, z)' + '\n' + + '}' + ) + + c_src5 = ( + 'int fun()' + '\n' + + '{' + '\n' + + 'return 1;' + '\n' + + '}' + '\n' + + 'void caller()' + '\n' + + '{' + '\n' + + 'int a = fun()' + '\n' + + '}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + + + assert res1[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun1'), + parameters=(Variable(Symbol('x'), + type=IntBaseType(String('intc')) + ), + ), + body=CodeBlock( + Return('x') + ) + ) + + assert res1[1] == FunctionDefinition( + NoneToken(), + name=String('caller'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('x'), + value=FunctionCall(String('fun1'), + function_args=( + Integer(2), + ) + ) + ) + ) + ) + ) + + assert res2[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun2'), + parameters=(Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ), + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ), + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + body=CodeBlock( + Return('a') + ) + ) + + assert res2[1] == FunctionDefinition( + NoneToken(), + name=String('caller'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('y'), + value=FunctionCall( + String('fun2'), + function_args=( + Integer(2), + Integer(3), + Integer(4) + ) + ) + ) + ) + ) + ) + + assert res3[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun3'), + parameters=( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ), + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ), + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + body=CodeBlock( + Return('b') + ) + ) + + assert res3[1] == FunctionDefinition( + NoneToken(), + name=String('caller'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('p'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('q'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('r'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('z'), + value=FunctionCall( + String('fun3'), + function_args=( + Symbol('p'), + Symbol('q'), + Symbol('r') + ) + ) + ) + ) + ) + ) + + assert res4[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun4'), + parameters=(Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ), + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ), + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + body=CodeBlock( + Return('c') + ) + ) + + assert res4[1] == FunctionDefinition( + NoneToken(), + name=String('caller'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('x'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Declaration( + Variable(Symbol('y'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Declaration( + Variable(Symbol('z'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('i'), + value=FunctionCall(String('fun4'), + function_args=( + Symbol('x'), + Symbol('y'), + Symbol('z') + ) + ) + ) + ) + ) + ) + + assert res5[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('fun'), + parameters=(), + body=CodeBlock( + Return('') + ) + ) + + assert res5[1] == FunctionDefinition( + NoneToken(), + name=String('caller'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + value=FunctionCall(String('fun'), + function_args=() + ) + ) + ) + ) + ) + + + def test_parse(): + c_src1 = ( + 'int a;' + '\n' + + 'int b;' + '\n' + ) + c_src2 = ( + 'void fun1()' + '\n' + + '{' + '\n' + + 'int a;' + '\n' + + '}' + ) + + f1 = open('..a.h', 'w') + f2 = open('..b.h', 'w') + + f1.write(c_src1) + f2. write(c_src2) + + f1.close() + f2.close() + + res1 = SymPyExpression('..a.h', 'c').return_expr() + res2 = SymPyExpression('..b.h', 'c').return_expr() + + os.remove('..a.h') + os.remove('..b.h') + + assert res1[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + assert res1[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')) + ) + ) + assert res2[0] == FunctionDefinition( + NoneToken(), + name=String('fun1'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + ) + ) + + + def test_binary_operators(): + c_src1 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = 1;' + '\n' + + '}' + ) + c_src2 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 0;' + '\n' + + 'a = a + 1;' + '\n' + + 'a = 3*a - 10;' + '\n' + + '}' + ) + c_src3 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 10;' + '\n' + + 'a = 1 + a - 3 * 6;' + '\n' + + '}' + ) + c_src4 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'int b;' + '\n' + + 'a = 100;' + '\n' + + 'b = a*a + a*a + a + 19*a + 1 + 24;' + '\n' + + '}' + ) + c_src5 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'int b;' + '\n' + + 'int c;' + '\n' + + 'int d;' + '\n' + + 'a = 1;' + '\n' + + 'b = 2;' + '\n' + + 'c = b;' + '\n' + + 'd = ((a+b)*(a+c))*((c-d)*(a+c));' + '\n' + + '}' + ) + c_src6 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'int b;' + '\n' + + 'int c;' + '\n' + + 'int d;' + '\n' + + 'a = 1;' + '\n' + + 'b = 2;' + '\n' + + 'c = 3;' + '\n' + + 'd = (a*a*a*a + 3*b*b + b + b + c*d);' + '\n' + + '}' + ) + c_src7 = ( + 'void func()'+ + '{' + '\n' + + 'float a;' + '\n' + + 'a = 1.01;' + '\n' + + '}' + ) + + c_src8 = ( + 'void func()'+ + '{' + '\n' + + 'float a;' + '\n' + + 'a = 10.0 + 2.5;' + '\n' + + '}' + ) + + c_src9 = ( + 'void func()'+ + '{' + '\n' + + 'float a;' + '\n' + + 'a = 10.0 / 2.5;' + '\n' + + '}' + ) + + c_src10 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = 100 / 4;' + '\n' + + '}' + ) + + c_src11 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = 20 - 100 / 4 * 5 + 10;' + '\n' + + '}' + ) + + c_src12 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = (20 - 100) / 4 * (5 + 10);' + '\n' + + '}' + ) + + c_src13 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'int b;' + '\n' + + 'float c;' + '\n' + + 'c = b/a;' + '\n' + + '}' + ) + + c_src14 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 2;' + '\n' + + 'int d = 5;' + '\n' + + 'int n = 10;' + '\n' + + 'int s;' + '\n' + + 's = (a/2)*(2*a + (n-1)*d);' + '\n' + + '}' + ) + + c_src15 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = 1 % 2;' + '\n' + + '}' + ) + + c_src16 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 2;' + '\n' + + 'int b;' + '\n' + + 'b = a % 3;' + '\n' + + '}' + ) + + c_src17 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int c;' + '\n' + + 'c = a % b;' + '\n' + + '}' + ) + + c_src18 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int mod = 1000000007;' + '\n' + + 'int c;' + '\n' + + 'c = (a + b * (100/a)) % mod;' + '\n' + + '}' + ) + + c_src19 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int mod = 1000000007;' + '\n' + + 'int c;' + '\n' + + 'c = ((a % mod + b % mod) % mod' \ + '* (a % mod - b % mod) % mod) % mod;' + '\n' + + '}' + ) + + c_src20 = ( + 'void func()'+ + '{' + '\n' + + 'bool a' + '\n' + + 'bool b;' + '\n' + + 'a = 1 == 2;' + '\n' + + 'b = 1 != 2;' + '\n' + + '}' + ) + + c_src21 = ( + 'void func()'+ + '{' + '\n' + + 'bool a;' + '\n' + + 'bool b;' + '\n' + + 'bool c;' + '\n' + + 'bool d;' + '\n' + + 'a = 1 == 2;' + '\n' + + 'b = 1 <= 2;' + '\n' + + 'c = 1 > 2;' + '\n' + + 'd = 1 >= 2;' + '\n' + + '}' + ) + + c_src22 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 1;' + '\n' + + 'int b = 2;' + '\n' + + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + 'bool c7;' + '\n' + + 'bool c8;' + '\n' + + + 'c1 = a == 1;' + '\n' + + 'c2 = b == 2;' + '\n' + + + 'c3 = 1 != a;' + '\n' + + 'c4 = 1 != b;' + '\n' + + + 'c5 = a < 0;' + '\n' + + 'c6 = b <= 10;' + '\n' + + 'c7 = a > 0;' + '\n' + + 'c8 = b >= 11;' + '\n' + + '}' + ) + + c_src23 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 3;' + '\n' + + 'int b = 4;' + '\n' + + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + + 'c1 = a == b;' + '\n' + + 'c2 = a != b;' + '\n' + + 'c3 = a < b;' + '\n' + + 'c4 = a <= b;' + '\n' + + 'c5 = a > b;' + '\n' + + 'c6 = a >= b;' + '\n' + + '}' + ) + + c_src24 = ( + 'void func()'+ + '{' + '\n' + + 'float a = 1.25' + 'float b = 2.5;' + '\n' + + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + + 'c1 = a == 1.25;' + '\n' + + 'c2 = b == 2.54;' + '\n' + + + 'c3 = 1.2 != a;' + '\n' + + 'c4 = 1.5 != b;' + '\n' + + '}' + ) + + c_src25 = ( + 'void func()'+ + '{' + '\n' + + 'float a = 1.25' + '\n' + + 'float b = 2.5;' + '\n' + + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + + 'c1 = a == b;' + '\n' + + 'c2 = a != b;' + '\n' + + 'c3 = a < b;' + '\n' + + 'c4 = a <= b;' + '\n' + + 'c5 = a > b;' + '\n' + + 'c6 = a >= b;' + '\n' + + '}' + ) + + c_src26 = ( + 'void func()'+ + '{' + '\n' + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + + 'c1 = true == true;' + '\n' + + 'c2 = true == false;' + '\n' + + 'c3 = false == false;' + '\n' + + + 'c4 = true != true;' + '\n' + + 'c5 = true != false;' + '\n' + + 'c6 = false != false;' + '\n' + + '}' + ) + + c_src27 = ( + 'void func()'+ + '{' + '\n' + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + + 'c1 = true && true;' + '\n' + + 'c2 = true && false;' + '\n' + + 'c3 = false && false;' + '\n' + + + 'c4 = true || true;' + '\n' + + 'c5 = true || false;' + '\n' + + 'c6 = false || false;' + '\n' + + '}' + ) + + c_src28 = ( + 'void func()'+ + '{' + '\n' + + 'bool a;' + '\n' + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + + 'c1 = a && true;' + '\n' + + 'c2 = false && a;' + '\n' + + + 'c3 = true || a;' + '\n' + + 'c4 = a || false;' + '\n' + + '}' + ) + + c_src29 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + + 'c1 = a && 1;' + '\n' + + 'c2 = a && 0;' + '\n' + + + 'c3 = a || 1;' + '\n' + + 'c4 = 0 || a;' + '\n' + + '}' + ) + + c_src30 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'int b;' + '\n' + + 'bool c;'+ '\n' + + 'bool d;'+ '\n' + + + 'bool c1;' + '\n' + + 'bool c2;' + '\n' + + 'bool c3;' + '\n' + + 'bool c4;' + '\n' + + 'bool c5;' + '\n' + + 'bool c6;' + '\n' + + + 'c1 = a && b;' + '\n' + + 'c2 = a && c;' + '\n' + + 'c3 = c && d;' + '\n' + + + 'c4 = a || b;' + '\n' + + 'c5 = a || c;' + '\n' + + 'c6 = c || d;' + '\n' + + '}' + ) + + c_src_raise1 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = -1;' + '\n' + + '}' + ) + + c_src_raise2 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = -+1;' + '\n' + + '}' + ) + + c_src_raise3 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = 2*-2;' + '\n' + + '}' + ) + + c_src_raise4 = ( + 'void func()'+ + '{' + '\n' + + 'int a;' + '\n' + + 'a = (int)2.0;' + '\n' + + '}' + ) + + c_src_raise5 = ( + 'void func()'+ + '{' + '\n' + + 'int a=100;' + '\n' + + 'a = (a==100)?(1):(0);' + '\n' + + '}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + res6 = SymPyExpression(c_src6, 'c').return_expr() + res7 = SymPyExpression(c_src7, 'c').return_expr() + res8 = SymPyExpression(c_src8, 'c').return_expr() + res9 = SymPyExpression(c_src9, 'c').return_expr() + res10 = SymPyExpression(c_src10, 'c').return_expr() + res11 = SymPyExpression(c_src11, 'c').return_expr() + res12 = SymPyExpression(c_src12, 'c').return_expr() + res13 = SymPyExpression(c_src13, 'c').return_expr() + res14 = SymPyExpression(c_src14, 'c').return_expr() + res15 = SymPyExpression(c_src15, 'c').return_expr() + res16 = SymPyExpression(c_src16, 'c').return_expr() + res17 = SymPyExpression(c_src17, 'c').return_expr() + res18 = SymPyExpression(c_src18, 'c').return_expr() + res19 = SymPyExpression(c_src19, 'c').return_expr() + res20 = SymPyExpression(c_src20, 'c').return_expr() + res21 = SymPyExpression(c_src21, 'c').return_expr() + res22 = SymPyExpression(c_src22, 'c').return_expr() + res23 = SymPyExpression(c_src23, 'c').return_expr() + res24 = SymPyExpression(c_src24, 'c').return_expr() + res25 = SymPyExpression(c_src25, 'c').return_expr() + res26 = SymPyExpression(c_src26, 'c').return_expr() + res27 = SymPyExpression(c_src27, 'c').return_expr() + res28 = SymPyExpression(c_src28, 'c').return_expr() + res29 = SymPyExpression(c_src29, 'c').return_expr() + res30 = SymPyExpression(c_src30, 'c').return_expr() + + assert res1[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Assignment(Variable(Symbol('a')), Integer(1)) + ) + ) + + assert res2[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(0))), + Assignment( + Variable(Symbol('a')), + Add(Symbol('a'), + Integer(1)) + ), + Assignment(Variable(Symbol('a')), + Add( + Mul( + Integer(3), + Symbol('a')), + Integer(-10) + ) + ) + ) + ) + + assert res3[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ), + Assignment( + Variable(Symbol('a')), + Add( + Symbol('a'), + Integer(-17) + ) + ) + ) + ) + + assert res4[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(100)), + Assignment( + Variable(Symbol('b')), + Add( + Mul( + Integer(2), + Pow( + Symbol('a'), + Integer(2)) + ), + Mul( + Integer(20), + Symbol('a')), + Integer(25) + ) + ) + ) + ) + + assert res5[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(1)), + Assignment( + Variable(Symbol('b')), + Integer(2) + ), + Assignment( + Variable(Symbol('c')), + Symbol('b')), + Assignment( + Variable(Symbol('d')), + Mul( + Add( + Symbol('a'), + Symbol('b')), + Pow( + Add( + Symbol('a'), + Symbol('c') + ), + Integer(2) + ), + Add( + Symbol('c'), + Mul( + Integer(-1), + Symbol('d') + ) + ) + ) + ) + ) + ) + + assert res6[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(1) + ), + Assignment( + Variable(Symbol('b')), + Integer(2) + ), + Assignment( + Variable(Symbol('c')), + Integer(3) + ), + Assignment( + Variable(Symbol('d')), + Add( + Pow( + Symbol('a'), + Integer(4) + ), + Mul( + Integer(3), + Pow( + Symbol('b'), + Integer(2) + ) + ), + Mul( + Integer(2), + Symbol('b') + ), + Mul( + Symbol('c'), + Symbol('d') + ) + ) + ) + ) + ) + + assert res7[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Assignment( + Variable(Symbol('a')), + Float('1.01', precision=53) + ) + ) + ) + + assert res8[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Assignment( + Variable(Symbol('a')), + Float('12.5', precision=53) + ) + ) + ) + + assert res9[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Assignment( + Variable(Symbol('a')), + Float('4.0', precision=53) + ) + ) + ) + + assert res10[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(25) + ) + ) + ) + + assert res11[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(-95) + ) + ) + ) + + assert res12[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(-300) + ) + ) + ) + + assert res13[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('c'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Assignment( + Variable(Symbol('c')), + Mul( + Pow( + Symbol('a'), + Integer(-1) + ), + Symbol('b') + ) + ) + ) + ) + + assert res14[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ), + Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')), + value=Integer(5) + ) + ), + Declaration( + Variable(Symbol('n'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ), + Declaration( + Variable(Symbol('s'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('s')), + Mul( + Rational(1, 2), + Symbol('a'), + Add( + Mul( + Integer(2), + Symbol('a') + ), + Mul( + Symbol('d'), + Add( + Symbol('n'), + Integer(-1) + ) + ) + ) + ) + ) + ) + ) + + assert res15[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('a')), + Integer(1) + ) + ) + ) + + assert res16[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('b')), + Mod( + Symbol('a'), + Integer(3) + ) + ) + ) + ) + + assert res17[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('c')), + Mod( + Symbol('a'), + Symbol('b') + ) + ) + ) + ) + + assert res18[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ), + Declaration( + Variable(Symbol('mod'), + type=IntBaseType(String('intc')), + value=Integer(1000000007) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('c')), + Mod( + Add( + Symbol('a'), + Mul( + Integer(100), + Pow( + Symbol('a'), + Integer(-1) + ), + Symbol('b') + ) + ), + Symbol('mod') + ) + ) + ) + ) + + assert res19[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ), + Declaration( + Variable(Symbol('mod'), + type=IntBaseType(String('intc')), + value=Integer(1000000007) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')) + ) + ), + Assignment( + Variable(Symbol('c')), + Mod( + Mul( + Add( + Mod( + Symbol('a'), + Symbol('mod') + ), + Mul( + Integer(-1), + Mod( + Symbol('b'), + Symbol('mod') + ) + ) + ), + Mod( + Add( + Symbol('a'), + Symbol('b') + ), + Symbol('mod') + ) + ), + Symbol('mod') + ) + ) + ) + ) + + assert res20[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('a')), + false + ), + Assignment( + Variable(Symbol('b')), + true + ) + ) + ) + + assert res21[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('d'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('a')), + false + ), + Assignment( + Variable(Symbol('b')), + true + ), + Assignment( + Variable(Symbol('c')), + false + ), + Assignment( + Variable(Symbol('d')), + false + ) + ) + ) + + assert res22[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c7'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c8'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Equality( + Symbol('a'), + Integer(1) + ) + ), + Assignment( + Variable(Symbol('c2')), + Equality( + Symbol('b'), + Integer(2) + ) + ), + Assignment( + Variable(Symbol('c3')), + Unequality( + Integer(1), + Symbol('a') + ) + ), + Assignment( + Variable(Symbol('c4')), + Unequality( + Integer(1), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c5')), + StrictLessThan( + Symbol('a'), + Integer(0) + ) + ), + Assignment( + Variable(Symbol('c6')), + LessThan( + Symbol('b'), + Integer(10) + ) + ), + Assignment( + Variable(Symbol('c7')), + StrictGreaterThan( + Symbol('a'), + Integer(0) + ) + ), + Assignment( + Variable(Symbol('c8')), + GreaterThan( + Symbol('b'), + Integer(11) + ) + ) + ) + ) + + assert res23[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(4) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Equality( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c2')), + Unequality( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c3')), + StrictLessThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c4')), + LessThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c5')), + StrictGreaterThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c6')), + GreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + ) + + assert res24[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Equality( + Symbol('a'), + Float('1.25', precision=53) + ) + ), + Assignment( + Variable(Symbol('c3')), + Unequality( + Float('1.2', precision=53), + Symbol('a') + ) + ) + ) + ) + + + assert res25[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.25', precision=53) + ) + ), + Declaration( + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.5', precision=53) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool') + ) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Equality( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c2')), + Unequality( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c3')), + StrictLessThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c4')), + LessThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c5')), + StrictGreaterThan( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c6')), + GreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + ) + + assert res26[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), body=CodeBlock( + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + true + ), + Assignment( + Variable(Symbol('c2')), + false + ), + Assignment( + Variable(Symbol('c3')), + true + ), + Assignment( + Variable(Symbol('c4')), + false + ), + Assignment( + Variable(Symbol('c5')), + true + ), + Assignment( + Variable(Symbol('c6')), + false + ) + ) + ) + + assert res27[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + true + ), + Assignment( + Variable(Symbol('c2')), + false + ), + Assignment( + Variable(Symbol('c3')), + false + ), + Assignment( + Variable(Symbol('c4')), + true + ), + Assignment( + Variable(Symbol('c5')), + true + ), + Assignment( + Variable(Symbol('c6')), + false) + ) + ) + + assert res28[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Symbol('a') + ), + Assignment( + Variable(Symbol('c2')), + false + ), + Assignment( + Variable(Symbol('c3')), + true + ), + Assignment( + Variable(Symbol('c4')), + Symbol('a') + ) + ) + ) + + assert res29[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + Symbol('a') + ), + Assignment( + Variable(Symbol('c2')), + false + ), + Assignment( + Variable(Symbol('c3')), + true + ), + Assignment( + Variable(Symbol('c4')), + Symbol('a') + ) + ) + ) + + assert res30[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')) + ) + ), + Declaration( + Variable(Symbol('c'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('d'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')) + ) + ), + Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')) + ) + ), + Assignment( + Variable(Symbol('c1')), + And( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c2')), + And( + Symbol('a'), + Symbol('c') + ) + ), + Assignment( + Variable(Symbol('c3')), + And( + Symbol('c'), + Symbol('d') + ) + ), + Assignment( + Variable(Symbol('c4')), + Or( + Symbol('a'), + Symbol('b') + ) + ), + Assignment( + Variable(Symbol('c5')), + Or( + Symbol('a'), + Symbol('c') + ) + ), + Assignment( + Variable(Symbol('c6')), + Or( + Symbol('c'), + Symbol('d') + ) + ) + ) + ) + + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise3, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise4, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise5, 'c')) + + + @XFAIL + def test_var_decl(): + c_src1 = ( + 'int b = 100;' + '\n' + + 'int a = b;' + '\n' + ) + + c_src2 = ( + 'int a = 1;' + '\n' + + 'int b = a + 1;' + '\n' + ) + + c_src3 = ( + 'float a = 10.0 + 2.5;' + '\n' + + 'float b = a * 20.0;' + '\n' + ) + + c_src4 = ( + 'int a = 1 + 100 - 3 * 6;' + '\n' + ) + + c_src5 = ( + 'int a = (((1 + 100) * 12) - 3) * (6 - 10);' + '\n' + ) + + c_src6 = ( + 'int b = 2;' + '\n' + + 'int c = 3;' + '\n' + + 'int a = b + c * 4;' + '\n' + ) + + c_src7 = ( + 'int b = 1;' + '\n' + + 'int c = b + 2;' + '\n' + + 'int a = 10 * b * b * c;' + '\n' + ) + + c_src8 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 1;' + '\n' + + 'int b = 2;' + '\n' + + 'int temp = a;' + '\n' + + 'a = b;' + '\n' + + 'b = temp;' + '\n' + + '}' + ) + + c_src9 = ( + 'int a = 1;' + '\n' + + 'int b = 2;' + '\n' + + 'int c = a;' + '\n' + + 'int d = a + b + c;' + '\n' + + 'int e = a*a*a + 3*a*a*b + 3*a*b*b + b*b*b;' + '\n' + 'int f = (a + b + c) * (a + b - c);' + '\n' + + 'int g = (a + b + c + d)*(a + b + c + d)*(a * (b - c));' + + '\n' + ) + + c_src10 = ( + 'float a = 10.0;' + '\n' + + 'float b = 2.5;' + '\n' + + 'float c = a*a + 2*a*b + b*b;' + '\n' + ) + + c_src11 = ( + 'float a = 10.0 / 2.5;' + '\n' + ) + + c_src12 = ( + 'int a = 100 / 4;' + '\n' + ) + + c_src13 = ( + 'int a = 20 - 100 / 4 * 5 + 10;' + '\n' + ) + + c_src14 = ( + 'int a = (20 - 100) / 4 * (5 + 10);' + '\n' + ) + + c_src15 = ( + 'int a = 4;' + '\n' + + 'int b = 2;' + '\n' + + 'float c = b/a;' + '\n' + ) + + c_src16 = ( + 'int a = 2;' + '\n' + + 'int d = 5;' + '\n' + + 'int n = 10;' + '\n' + + 'int s = (a/2)*(2*a + (n-1)*d);' + '\n' + ) + + c_src17 = ( + 'int a = 1 % 2;' + '\n' + ) + + c_src18 = ( + 'int a = 2;' + '\n' + + 'int b = a % 3;' + '\n' + ) + + c_src19 = ( + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int c = a % b;' + '\n' + ) + + c_src20 = ( + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int mod = 1000000007;' + '\n' + + 'int c = (a + b * (100/a)) % mod;' + '\n' + ) + + c_src21 = ( + 'int a = 100;' + '\n' + + 'int b = 3;' + '\n' + + 'int mod = 1000000007;' + '\n' + + 'int c = ((a % mod + b % mod) % mod *' \ + '(a % mod - b % mod) % mod) % mod;' + '\n' + ) + + c_src22 = ( + 'bool a = 1 == 2, b = 1 != 2;' + ) + + c_src23 = ( + 'bool a = 1 < 2, b = 1 <= 2, c = 1 > 2, d = 1 >= 2;' + ) + + c_src24 = ( + 'int a = 1, b = 2;' + '\n' + + + 'bool c1 = a == 1;' + '\n' + + 'bool c2 = b == 2;' + '\n' + + + 'bool c3 = 1 != a;' + '\n' + + 'bool c4 = 1 != b;' + '\n' + + + 'bool c5 = a < 0;' + '\n' + + 'bool c6 = b <= 10;' + '\n' + + 'bool c7 = a > 0;' + '\n' + + 'bool c8 = b >= 11;' + + ) + + c_src25 = ( + 'int a = 3, b = 4;' + '\n' + + + 'bool c1 = a == b;' + '\n' + + 'bool c2 = a != b;' + '\n' + + 'bool c3 = a < b;' + '\n' + + 'bool c4 = a <= b;' + '\n' + + 'bool c5 = a > b;' + '\n' + + 'bool c6 = a >= b;' + ) + + c_src26 = ( + 'float a = 1.25, b = 2.5;' + '\n' + + + 'bool c1 = a == 1.25;' + '\n' + + 'bool c2 = b == 2.54;' + '\n' + + + 'bool c3 = 1.2 != a;' + '\n' + + 'bool c4 = 1.5 != b;' + ) + + c_src27 = ( + 'float a = 1.25, b = 2.5;' + '\n' + + + 'bool c1 = a == b;' + '\n' + + 'bool c2 = a != b;' + '\n' + + 'bool c3 = a < b;' + '\n' + + 'bool c4 = a <= b;' + '\n' + + 'bool c5 = a > b;' + '\n' + + 'bool c6 = a >= b;' + ) + + c_src28 = ( + 'bool c1 = true == true;' + '\n' + + 'bool c2 = true == false;' + '\n' + + 'bool c3 = false == false;' + '\n' + + + 'bool c4 = true != true;' + '\n' + + 'bool c5 = true != false;' + '\n' + + 'bool c6 = false != false;' + ) + + c_src29 = ( + 'bool c1 = true && true;' + '\n' + + 'bool c2 = true && false;' + '\n' + + 'bool c3 = false && false;' + '\n' + + + 'bool c4 = true || true;' + '\n' + + 'bool c5 = true || false;' + '\n' + + 'bool c6 = false || false;' + ) + + c_src30 = ( + 'bool a = false;' + '\n' + + + 'bool c1 = a && true;' + '\n' + + 'bool c2 = false && a;' + '\n' + + + 'bool c3 = true || a;' + '\n' + + 'bool c4 = a || false;' + ) + + c_src31 = ( + 'int a = 1;' + '\n' + + + 'bool c1 = a && 1;' + '\n' + + 'bool c2 = a && 0;' + '\n' + + + 'bool c3 = a || 1;' + '\n' + + 'bool c4 = 0 || a;' + ) + + c_src32 = ( + 'int a = 1, b = 0;' + '\n' + + 'bool c = false, d = true;'+ '\n' + + + 'bool c1 = a && b;' + '\n' + + 'bool c2 = a && c;' + '\n' + + 'bool c3 = c && d;' + '\n' + + + 'bool c4 = a || b;' + '\n' + + 'bool c5 = a || c;' + '\n' + + 'bool c6 = c || d;' + ) + + c_src_raise1 = ( + "char a = 'b';" + ) + + c_src_raise2 = ( + 'int a[] = {10, 20};' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + res6 = SymPyExpression(c_src6, 'c').return_expr() + res7 = SymPyExpression(c_src7, 'c').return_expr() + res8 = SymPyExpression(c_src8, 'c').return_expr() + res9 = SymPyExpression(c_src9, 'c').return_expr() + res10 = SymPyExpression(c_src10, 'c').return_expr() + res11 = SymPyExpression(c_src11, 'c').return_expr() + res12 = SymPyExpression(c_src12, 'c').return_expr() + res13 = SymPyExpression(c_src13, 'c').return_expr() + res14 = SymPyExpression(c_src14, 'c').return_expr() + res15 = SymPyExpression(c_src15, 'c').return_expr() + res16 = SymPyExpression(c_src16, 'c').return_expr() + res17 = SymPyExpression(c_src17, 'c').return_expr() + res18 = SymPyExpression(c_src18, 'c').return_expr() + res19 = SymPyExpression(c_src19, 'c').return_expr() + res20 = SymPyExpression(c_src20, 'c').return_expr() + res21 = SymPyExpression(c_src21, 'c').return_expr() + res22 = SymPyExpression(c_src22, 'c').return_expr() + res23 = SymPyExpression(c_src23, 'c').return_expr() + res24 = SymPyExpression(c_src24, 'c').return_expr() + res25 = SymPyExpression(c_src25, 'c').return_expr() + res26 = SymPyExpression(c_src26, 'c').return_expr() + res27 = SymPyExpression(c_src27, 'c').return_expr() + res28 = SymPyExpression(c_src28, 'c').return_expr() + res29 = SymPyExpression(c_src29, 'c').return_expr() + res30 = SymPyExpression(c_src30, 'c').return_expr() + res31 = SymPyExpression(c_src31, 'c').return_expr() + res32 = SymPyExpression(c_src32, 'c').return_expr() + + assert res1[0] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ) + + assert res1[1] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Symbol('b') + ) + ) + + assert res2[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res2[1] == Declaration(Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('a'), + Integer(1) + ) + ) + ) + + assert res3[0] == Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('12.5', precision=53) + ) + ) + + assert res3[1] == Declaration( + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Mul( + Float('20.0', precision=53), + Symbol('a') + ) + ) + ) + + assert res4[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(83) + ) + ) + + assert res5[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(-4836) + ) + ) + + assert res6[0] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res6[1] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res6[2] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('b'), + Mul( + Integer(4), + Symbol('c') + ) + ) + ) + ) + + assert res7[0] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res7[1] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('b'), + Integer(2) + ) + ) + ) + + assert res7[2] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Mul( + Integer(10), + Pow( + Symbol('b'), + Integer(2) + ), + Symbol('c') + ) + ) + ) + + assert res8[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ), + Declaration( + Variable(Symbol('temp'), + type=IntBaseType(String('intc')), + value=Symbol('a') + ) + ), + Assignment( + Variable(Symbol('a')), + Symbol('b') + ), + Assignment( + Variable(Symbol('b')), + Symbol('temp') + ) + ) + ) + + assert res9[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res9[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res9[2] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Symbol('a') + ) + ) + + assert res9[3] == Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('a'), + Symbol('b'), + Symbol('c') + ) + ) + ) + + assert res9[4] == Declaration( + Variable(Symbol('e'), + type=IntBaseType(String('intc')), + value=Add( + Pow( + Symbol('a'), + Integer(3) + ), + Mul( + Integer(3), + Pow( + Symbol('a'), + Integer(2) + ), + Symbol('b') + ), + Mul( + Integer(3), + Symbol('a'), + Pow( + Symbol('b'), + Integer(2) + ) + ), + Pow( + Symbol('b'), + Integer(3) + ) + ) + ) + ) + + assert res9[5] == Declaration( + Variable(Symbol('f'), + type=IntBaseType(String('intc')), + value=Mul( + Add( + Symbol('a'), + Symbol('b'), + Mul( + Integer(-1), + Symbol('c') + ) + ), + Add( + Symbol('a'), + Symbol('b'), + Symbol('c') + ) + ) + ) + ) + + assert res9[6] == Declaration( + Variable(Symbol('g'), + type=IntBaseType(String('intc')), + value=Mul( + Symbol('a'), + Add( + Symbol('b'), + Mul( + Integer(-1), + Symbol('c') + ) + ), + Pow( + Add( + Symbol('a'), + Symbol('b'), + Symbol('c'), + Symbol('d') + ), + Integer(2) + ) + ) + ) + ) + + assert res10[0] == Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('10.0', precision=53) + ) + ) + + assert res10[1] == Declaration( + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.5', precision=53) + ) + ) + + assert res10[2] == Declaration( + Variable(Symbol('c'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Add( + Pow( + Symbol('a'), + Integer(2) + ), + Mul( + Integer(2), + Symbol('a'), + Symbol('b') + ), + Pow( + Symbol('b'), + Integer(2) + ) + ) + ) + ) + + assert res11[0] == Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('4.0', precision=53) + ) + ) + + assert res12[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(25) + ) + ) + + assert res13[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(-95) + ) + ) + + assert res14[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(-300) + ) + ) + + assert res15[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(4) + ) + ) + + assert res15[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res15[2] == Declaration( + Variable(Symbol('c'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Mul( + Pow( + Symbol('a'), + Integer(-1) + ), + Symbol('b') + ) + ) + ) + + assert res16[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res16[1] == Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')), + value=Integer(5) + ) + ) + + assert res16[2] == Declaration( + Variable(Symbol('n'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ) + + assert res16[3] == Declaration( + Variable(Symbol('s'), + type=IntBaseType(String('intc')), + value=Mul( + Rational(1, 2), + Symbol('a'), + Add( + Mul( + Integer(2), + Symbol('a') + ), + Mul( + Symbol('d'), + Add( + Symbol('n'), + Integer(-1) + ) + ) + ) + ) + ) + ) + + assert res17[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res18[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res18[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Mod( + Symbol('a'), + Integer(3) + ) + ) + ) + + assert res19[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ) + assert res19[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res19[2] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Mod( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res20[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ) + + assert res20[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res20[2] == Declaration( + Variable(Symbol('mod'), + type=IntBaseType(String('intc')), + value=Integer(1000000007) + ) + ) + + assert res20[3] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Mod( + Add( + Symbol('a'), + Mul( + Integer(100), + Pow( + Symbol('a'), + Integer(-1) + ), + Symbol('b') + ) + ), + Symbol('mod') + ) + ) + ) + + assert res21[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ) + + assert res21[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res21[2] == Declaration( + Variable(Symbol('mod'), + type=IntBaseType(String('intc')), + value=Integer(1000000007) + ) + ) + + assert res21[3] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Mod( + Mul( + Add( + Symbol('a'), + Mul( + Integer(-1), + Symbol('b') + ) + ), + Add( + Symbol('a'), + Symbol('b') + ) + ), + Symbol('mod') + ) + ) + ) + + assert res22[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=false + ) + ) + + assert res22[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=true + ) + ) + + assert res23[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=true + ) + ) + + assert res23[1] == Declaration( + Variable(Symbol('b'), + type=Type(String('bool')), + value=true + ) + ) + + assert res23[2] == Declaration( + Variable(Symbol('c'), + type=Type(String('bool')), + value=false + ) + ) + + assert res23[3] == Declaration( + Variable(Symbol('d'), + type=Type(String('bool')), + value=false + ) + ) + + assert res24[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res24[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res24[2] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=Equality( + Symbol('a'), + Integer(1) + ) + ) + ) + + assert res24[3] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=Equality( + Symbol('b'), + Integer(2) + ) + ) + ) + + assert res24[4] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=Unequality( + Integer(1), + Symbol('a') + ) + ) + ) + + assert res24[5] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=Unequality( + Integer(1), + Symbol('b') + ) + ) + ) + + assert res24[6] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=StrictLessThan(Symbol('a'), + Integer(0) + ) + ) + ) + + assert res24[7] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=LessThan( + Symbol('b'), + Integer(10) + ) + ) + ) + + assert res24[8] == Declaration( + Variable(Symbol('c7'), + type=Type(String('bool')), + value=StrictGreaterThan( + Symbol('a'), + Integer(0) + ) + ) + ) + + assert res24[9] == Declaration( + Variable(Symbol('c8'), + type=Type(String('bool')), + value=GreaterThan( + Symbol('b'), + Integer(11) + ) + ) + ) + + assert res25[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res25[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(4) + ) + ) + + assert res25[2] == Declaration(Variable(Symbol('c1'), + type=Type(String('bool')), + value=Equality( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res25[3] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=Unequality( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res25[4] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=StrictLessThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res25[5] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=LessThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res25[6] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=StrictGreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res25[7] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=GreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res26[0] == Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.25', precision=53) + ) + ) + + assert res26[1] == Declaration( + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.5', precision=53) + ) + ) + + assert res26[2] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=Equality( + Symbol('a'), + Float('1.25', precision=53) + ) + ) + ) + + assert res26[3] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=Equality( + Symbol('b'), + Float('2.54', precision=53) + ) + ) + ) + + assert res26[4] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=Unequality( + Float('1.2', precision=53), + Symbol('a') + ) + ) + ) + + assert res26[5] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=Unequality( + Float('1.5', precision=53), + Symbol('b') + ) + ) + ) + + assert res27[0] == Declaration( + Variable(Symbol('a'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('1.25', precision=53) + ) + ) + + assert res27[1] == Declaration( + Variable(Symbol('b'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.5', precision=53) + ) + ) + + assert res27[2] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=Equality( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res27[3] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=Unequality( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res27[4] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=StrictLessThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res27[5] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=LessThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res27[6] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=StrictGreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res27[7] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=GreaterThan( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res28[0] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=true + ) + ) + + assert res28[1] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=false + ) + ) + + assert res28[2] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=true + ) + ) + + assert res28[3] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=false + ) + ) + + assert res28[4] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=true + ) + ) + + assert res28[5] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=false + ) + ) + + assert res29[0] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=true + ) + ) + + assert res29[1] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=false + ) + ) + + assert res29[2] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=false + ) + ) + + assert res29[3] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=true + ) + ) + + assert res29[4] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=true + ) + ) + + assert res29[5] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=false + ) + ) + + assert res30[0] == Declaration( + Variable(Symbol('a'), + type=Type(String('bool')), + value=false + ) + ) + + assert res30[1] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=Symbol('a') + ) + ) + + assert res30[2] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=false + ) + ) + + assert res30[3] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=true + ) + ) + + assert res30[4] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=Symbol('a') + ) + ) + + assert res31[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res31[1] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=Symbol('a') + ) + ) + + assert res31[2] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=false + ) + ) + + assert res31[3] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=true + ) + ) + + assert res31[4] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=Symbol('a') + ) + ) + + assert res32[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res32[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(0) + ) + ) + + assert res32[2] == Declaration( + Variable(Symbol('c'), + type=Type(String('bool')), + value=false + ) + ) + + assert res32[3] == Declaration( + Variable(Symbol('d'), + type=Type(String('bool')), + value=true + ) + ) + + assert res32[4] == Declaration( + Variable(Symbol('c1'), + type=Type(String('bool')), + value=And( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res32[5] == Declaration( + Variable(Symbol('c2'), + type=Type(String('bool')), + value=And( + Symbol('a'), + Symbol('c') + ) + ) + ) + + assert res32[6] == Declaration( + Variable(Symbol('c3'), + type=Type(String('bool')), + value=And( + Symbol('c'), + Symbol('d') + ) + ) + ) + + assert res32[7] == Declaration( + Variable(Symbol('c4'), + type=Type(String('bool')), + value=Or( + Symbol('a'), + Symbol('b') + ) + ) + ) + + assert res32[8] == Declaration( + Variable(Symbol('c5'), + type=Type(String('bool')), + value=Or( + Symbol('a'), + Symbol('c') + ) + ) + ) + + assert res32[9] == Declaration( + Variable(Symbol('c6'), + type=Type(String('bool')), + value=Or( + Symbol('c'), + Symbol('d') + ) + ) + ) + + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) + + + def test_paren_expr(): + c_src1 = ( + 'int a = (1);' + 'int b = (1 + 2 * 3);' + ) + + c_src2 = ( + 'int a = 1, b = 2, c = 3;' + 'int d = (a);' + 'int e = (a + 1);' + 'int f = (a + b * c - d / e);' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + + assert res1[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res1[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(7) + ) + ) + + assert res2[0] == Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(1) + ) + ) + + assert res2[1] == Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(2) + ) + ) + + assert res2[2] == Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Integer(3) + ) + ) + + assert res2[3] == Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')), + value=Symbol('a') + ) + ) + + assert res2[4] == Declaration( + Variable(Symbol('e'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('a'), + Integer(1) + ) + ) + ) + + assert res2[5] == Declaration( + Variable(Symbol('f'), + type=IntBaseType(String('intc')), + value=Add( + Symbol('a'), + Mul( + Symbol('b'), + Symbol('c') + ), + Mul( + Integer(-1), + Symbol('d'), + Pow( + Symbol('e'), + Integer(-1) + ) + ) + ) + ) + ) + + + def test_unary_operators(): + c_src1 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 10;' + '\n' + + 'int b = 20;' + '\n' + + '++a;' + '\n' + + '--b;' + '\n' + + 'a++;' + '\n' + + 'b--;' + '\n' + + '}' + ) + + c_src2 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 10;' + '\n' + + 'int b = -100;' + '\n' + + 'int c = +19;' + '\n' + + 'int d = ++a;' + '\n' + + 'int e = --b;' + '\n' + + 'int f = a++;' + '\n' + + 'int g = b--;' + '\n' + + 'bool h = !false;' + '\n' + + 'bool i = !d;' + '\n' + + 'bool j = !0;' + '\n' + + 'bool k = !10.0;' + '\n' + + '}' + ) + + c_src_raise1 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 10;' + '\n' + + 'int b = ~a;' + '\n' + + '}' + ) + + c_src_raise2 = ( + 'void func()'+ + '{' + '\n' + + 'int a = 10;' + '\n' + + 'int b = *&a;' + '\n' + + '}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + + assert res1[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(20) + ) + ), + PreIncrement(Symbol('a')), + PreDecrement(Symbol('b')), + PostIncrement(Symbol('a')), + PostDecrement(Symbol('b')) + ) + ) + + assert res2[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ), + Declaration( + Variable(Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(-100) + ) + ), + Declaration( + Variable(Symbol('c'), + type=IntBaseType(String('intc')), + value=Integer(19) + ) + ), + Declaration( + Variable(Symbol('d'), + type=IntBaseType(String('intc')), + value=PreIncrement(Symbol('a')) + ) + ), + Declaration( + Variable(Symbol('e'), + type=IntBaseType(String('intc')), + value=PreDecrement(Symbol('b')) + ) + ), + Declaration( + Variable(Symbol('f'), + type=IntBaseType(String('intc')), + value=PostIncrement(Symbol('a')) + ) + ), + Declaration( + Variable(Symbol('g'), + type=IntBaseType(String('intc')), + value=PostDecrement(Symbol('b')) + ) + ), + Declaration( + Variable(Symbol('h'), + type=Type(String('bool')), + value=true + ) + ), + Declaration( + Variable(Symbol('i'), + type=Type(String('bool')), + value=Not(Symbol('d')) + ) + ), + Declaration( + Variable(Symbol('j'), + type=Type(String('bool')), + value=true + ) + ), + Declaration( + Variable(Symbol('k'), + type=Type(String('bool')), + value=false + ) + ) + ) + ) + + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) + raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) + + + def test_compound_assignment_operator(): + c_src = ( + 'void func()'+ + '{' + '\n' + + 'int a = 100;' + '\n' + + 'a += 10;' + '\n' + + 'a -= 10;' + '\n' + + 'a *= 10;' + '\n' + + 'a /= 10;' + '\n' + + 'a %= 10;' + '\n' + + '}' + ) + + res = SymPyExpression(c_src, 'c').return_expr() + + assert res[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')), + value=Integer(100) + ) + ), + AddAugmentedAssignment( + Variable(Symbol('a')), + Integer(10) + ), + SubAugmentedAssignment( + Variable(Symbol('a')), + Integer(10) + ), + MulAugmentedAssignment( + Variable(Symbol('a')), + Integer(10) + ), + DivAugmentedAssignment( + Variable(Symbol('a')), + Integer(10) + ), + ModAugmentedAssignment( + Variable(Symbol('a')), + Integer(10) + ) + ) + ) + + @XFAIL # this is expected to fail because of a bug in the C parser. + def test_while_stmt(): + c_src1 = ( + 'void func()'+ + '{' + '\n' + + 'int i = 0;' + '\n' + + 'while(i < 10)' + '\n' + + '{' + '\n' + + 'i++;' + '\n' + + '}' + '}' + ) + + c_src2 = ( + 'void func()'+ + '{' + '\n' + + 'int i = 0;' + '\n' + + 'while(i < 10)' + '\n' + + 'i++;' + '\n' + + '}' + ) + + c_src3 = ( + 'void func()'+ + '{' + '\n' + + 'int i = 10;' + '\n' + + 'int cnt = 0;' + '\n' + + 'while(i > 0)' + '\n' + + '{' + '\n' + + 'i--;' + '\n' + + 'cnt++;' + '\n' + + '}' + '\n' + + '}' + ) + + c_src4 = ( + 'int digit_sum(int n)'+ + '{' + '\n' + + 'int sum = 0;' + '\n' + + 'while(n > 0)' + '\n' + + '{' + '\n' + + 'sum += (n % 10);' + '\n' + + 'n /= 10;' + '\n' + + '}' + '\n' + + 'return sum;' + '\n' + + '}' + ) + + c_src5 = ( + 'void func()'+ + '{' + '\n' + + 'while(1);' + '\n' + + '}' + ) + + res1 = SymPyExpression(c_src1, 'c').return_expr() + res2 = SymPyExpression(c_src2, 'c').return_expr() + res3 = SymPyExpression(c_src3, 'c').return_expr() + res4 = SymPyExpression(c_src4, 'c').return_expr() + res5 = SymPyExpression(c_src5, 'c').return_expr() + + assert res1[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable(Symbol('i'), + type=IntBaseType(String('intc')), + value=Integer(0) + ) + ), + While( + StrictLessThan( + Symbol('i'), + Integer(10) + ), + body=CodeBlock( + PostIncrement( + Symbol('i') + ) + ) + ) + ) + ) + + assert res2[0] == res1[0] + + assert res3[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + Declaration( + Variable( + Symbol('i'), + type=IntBaseType(String('intc')), + value=Integer(10) + ) + ), + Declaration( + Variable( + Symbol('cnt'), + type=IntBaseType(String('intc')), + value=Integer(0) + ) + ), + While( + StrictGreaterThan( + Symbol('i'), + Integer(0) + ), + body=CodeBlock( + PostDecrement( + Symbol('i') + ), + PostIncrement( + Symbol('cnt') + ) + ) + ) + ) + ) + + assert res4[0] == FunctionDefinition( + IntBaseType(String('intc')), + name=String('digit_sum'), + parameters=( + Variable( + Symbol('n'), + type=IntBaseType(String('intc')) + ), + ), + body=CodeBlock( + Declaration( + Variable( + Symbol('sum'), + type=IntBaseType(String('intc')), + value=Integer(0) + ) + ), + While( + StrictGreaterThan( + Symbol('n'), + Integer(0) + ), + body=CodeBlock( + AddAugmentedAssignment( + Variable( + Symbol('sum') + ), + Mod( + Symbol('n'), + Integer(10) + ) + ), + DivAugmentedAssignment( + Variable( + Symbol('n') + ), + Integer(10) + ) + ) + ), + Return('sum') + ) + ) + + assert res5[0] == FunctionDefinition( + NoneToken(), + name=String('func'), + parameters=(), + body=CodeBlock( + While( + Integer(1), + body=CodeBlock( + NoneToken() + ) + ) + ) + ) + + +else: + def test_raise(): + from sympy.parsing.c.c_parser import CCodeConverter + raises(ImportError, lambda: CCodeConverter()) + raises(ImportError, lambda: SymPyExpression(' ', mode = 'c')) diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_implicit_multiplication_application.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_implicit_multiplication_application.py new file mode 100644 index 0000000000000000000000000000000000000000..5c713861f983b2ada656eafffb66723ea93c0611 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_implicit_multiplication_application.py @@ -0,0 +1,196 @@ +import sympy +from sympy.parsing.sympy_parser import ( + parse_expr, + standard_transformations, + convert_xor, + implicit_multiplication_application, + implicit_multiplication, + implicit_application, + function_exponentiation, + split_symbols, + split_symbols_custom, + _token_splittable +) +from sympy.testing.pytest import raises + + +def test_implicit_multiplication(): + cases = { + '5x': '5*x', + 'abc': 'a*b*c', + '3sin(x)': '3*sin(x)', + '(x+1)(x+2)': '(x+1)*(x+2)', + '(5 x**2)sin(x)': '(5*x**2)*sin(x)', + '2 sin(x) cos(x)': '2*sin(x)*cos(x)', + 'pi x': 'pi*x', + 'x pi': 'x*pi', + 'E x': 'E*x', + 'EulerGamma y': 'EulerGamma*y', + 'E pi': 'E*pi', + 'pi (x + 2)': 'pi*(x+2)', + '(x + 2) pi': '(x+2)*pi', + 'pi sin(x)': 'pi*sin(x)', + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (split_symbols, + implicit_multiplication) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + application = ['sin x', 'cos 2*x', 'sin cos x'] + for case in application: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + raises(TypeError, + lambda: parse_expr('sin**2(x)', transformations=transformations2)) + + +def test_implicit_application(): + cases = { + 'factorial': 'factorial', + 'sin x': 'sin(x)', + 'tan y**3': 'tan(y**3)', + 'cos 2*x': 'cos(2*x)', + '(cot)': 'cot', + 'sin cos tan x': 'sin(cos(tan(x)))' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (implicit_application,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal), (implicit, normal) + + multiplication = ['x y', 'x sin x', '2x'] + for case in multiplication: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + raises(TypeError, + lambda: parse_expr('sin**2(x)', transformations=transformations2)) + + +def test_function_exponentiation(): + cases = { + 'sin**2(x)': 'sin(x)**2', + 'exp^y(z)': 'exp(z)^y', + 'sin**2(E^(x))': 'sin(E^(x))**2' + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (function_exponentiation,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + other_implicit = ['x y', 'x sin x', '2x', 'sin x', + 'cos 2*x', 'sin cos x'] + for case in other_implicit: + raises(SyntaxError, + lambda: parse_expr(case, transformations=transformations2)) + + assert parse_expr('x**2', local_dict={ 'x': sympy.Symbol('x') }, + transformations=transformations2) == parse_expr('x**2') + + +def test_symbol_splitting(): + # By default Greek letter names should not be split (lambda is a keyword + # so skip it) + transformations = standard_transformations + (split_symbols,) + greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', + 'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi', + 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', + 'phi', 'chi', 'psi', 'omega') + + for letter in greek_letters: + assert(parse_expr(letter, transformations=transformations) == + parse_expr(letter)) + + # Make sure symbol splitting resolves names + transformations += (implicit_multiplication,) + local_dict = { 'e': sympy.E } + cases = { + 'xe': 'E*x', + 'Iy': 'I*y', + 'ee': 'E*E', + } + for case, expected in cases.items(): + assert(parse_expr(case, local_dict=local_dict, + transformations=transformations) == + parse_expr(expected)) + + # Make sure custom splitting works + def can_split(symbol): + if symbol not in ('unsplittable', 'names'): + return _token_splittable(symbol) + return False + transformations = standard_transformations + transformations += (split_symbols_custom(can_split), + implicit_multiplication) + + assert(parse_expr('unsplittable', transformations=transformations) == + parse_expr('unsplittable')) + assert(parse_expr('names', transformations=transformations) == + parse_expr('names')) + assert(parse_expr('xy', transformations=transformations) == + parse_expr('x*y')) + for letter in greek_letters: + assert(parse_expr(letter, transformations=transformations) == + parse_expr(letter)) + + +def test_all_implicit_steps(): + cases = { + '2x': '2*x', # implicit multiplication + 'x y': 'x*y', + 'xy': 'x*y', + 'sin x': 'sin(x)', # add parentheses + '2sin x': '2*sin(x)', + 'x y z': 'x*y*z', + 'sin(2 * 3x)': 'sin(2 * 3 * x)', + 'sin(x) (1 + cos(x))': 'sin(x) * (1 + cos(x))', + '(x + 2) sin(x)': '(x + 2) * sin(x)', + '(x + 2) sin x': '(x + 2) * sin(x)', + 'sin(sin x)': 'sin(sin(x))', + 'sin x!': 'sin(factorial(x))', + 'sin x!!': 'sin(factorial2(x))', + 'factorial': 'factorial', # don't apply a bare function + 'x sin x': 'x * sin(x)', # both application and multiplication + 'xy sin x': 'x * y * sin(x)', + '(x+2)(x+3)': '(x + 2) * (x+3)', + 'x**2 + 2xy + y**2': 'x**2 + 2 * x * y + y**2', # split the xy + 'pi': 'pi', # don't mess with constants + 'None': 'None', + 'ln sin x': 'ln(sin(x))', # multiple implicit function applications + 'factorial': 'factorial', # don't add parentheses + 'sin x**2': 'sin(x**2)', # implicit application to an exponential + 'alpha': 'Symbol("alpha")', # don't split Greek letters/subscripts + 'x_2': 'Symbol("x_2")', + 'sin^2 x**2': 'sin(x**2)**2', # function raised to a power + 'sin**3(x)': 'sin(x)**3', + '(factorial)': 'factorial', + 'tan 3x': 'tan(3*x)', + 'sin^2(3*E^(x))': 'sin(3*E**(x))**2', + 'sin**2(E^(3x))': 'sin(E**(3*x))**2', + 'sin^2 (3x*E^(x))': 'sin(3*x*E^x)**2', + 'pi sin x': 'pi*sin(x)', + } + transformations = standard_transformations + (convert_xor,) + transformations2 = transformations + (implicit_multiplication_application,) + for case in cases: + implicit = parse_expr(case, transformations=transformations2) + normal = parse_expr(cases[case], transformations=transformations) + assert(implicit == normal) + + +def test_no_methods_implicit_multiplication(): + # Issue 21020 + u = sympy.Symbol('u') + transformations = standard_transformations + \ + (implicit_multiplication,) + expr = parse_expr('x.is_polynomial(x)', transformations=transformations) + assert expr == True + expr = parse_expr('(exp(x) / (1 + exp(2x))).subs(exp(x), u)', + transformations=transformations) + assert expr == u/(u**2 + 1) diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_latex.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_latex.py new file mode 100644 index 0000000000000000000000000000000000000000..49a48966eacaa1cd7a242dcd0e7699c992bb1268 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_latex.py @@ -0,0 +1,358 @@ +from sympy.testing.pytest import raises, XFAIL +from sympy.external import import_module + +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.function import (Derivative, Function) +from sympy.core.mul import Mul +from sympy.core.numbers import (E, oo) +from sympy.core.power import Pow +from sympy.core.relational import (GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Unequality) +from sympy.core.symbol import Symbol +from sympy.functions.combinatorial.factorials import (binomial, factorial) +from sympy.functions.elementary.complexes import (Abs, conjugate) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.integers import (ceiling, floor) +from sympy.functions.elementary.miscellaneous import (root, sqrt) +from sympy.functions.elementary.trigonometric import (asin, cos, csc, sec, sin, tan) +from sympy.integrals.integrals import Integral +from sympy.series.limits import Limit + +from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge +from sympy.physics.quantum.state import Bra, Ket +from sympy.abc import x, y, z, a, b, c, t, k, n +antlr4 = import_module("antlr4") + +# disable tests if antlr4-python3-runtime is not present +disabled = antlr4 is None + +theta = Symbol('theta') +f = Function('f') + + +# shorthand definitions +def _Add(a, b): + return Add(a, b, evaluate=False) + + +def _Mul(a, b): + return Mul(a, b, evaluate=False) + + +def _Pow(a, b): + return Pow(a, b, evaluate=False) + + +def _Sqrt(a): + return sqrt(a, evaluate=False) + + +def _Conjugate(a): + return conjugate(a, evaluate=False) + + +def _Abs(a): + return Abs(a, evaluate=False) + + +def _factorial(a): + return factorial(a, evaluate=False) + + +def _exp(a): + return exp(a, evaluate=False) + + +def _log(a, b): + return log(a, b, evaluate=False) + + +def _binomial(n, k): + return binomial(n, k, evaluate=False) + + +def test_import(): + from sympy.parsing.latex._build_latex_antlr import ( + build_parser, + check_antlr_version, + dir_latex_antlr + ) + # XXX: It would be better to come up with a test for these... + del build_parser, check_antlr_version, dir_latex_antlr + + +# These LaTeX strings should parse to the corresponding SymPy expression +GOOD_PAIRS = [ + (r"0", 0), + (r"1", 1), + (r"-3.14", -3.14), + (r"(-7.13)(1.5)", _Mul(-7.13, 1.5)), + (r"x", x), + (r"2x", 2*x), + (r"x^2", x**2), + (r"x^\frac{1}{2}", _Pow(x, _Pow(2, -1))), + (r"x^{3 + 1}", x**_Add(3, 1)), + (r"-c", -c), + (r"a \cdot b", a * b), + (r"a / b", a / b), + (r"a \div b", a / b), + (r"a + b", a + b), + (r"a + b - a", _Add(a+b, -a)), + (r"a^2 + b^2 = c^2", Eq(a**2 + b**2, c**2)), + (r"(x + y) z", _Mul(_Add(x, y), z)), + (r"a'b+ab'", _Add(_Mul(Symbol("a'"), b), _Mul(a, Symbol("b'")))), + (r"y''_1", Symbol("y_{1}''")), + (r"y_1''", Symbol("y_{1}''")), + (r"\left(x + y\right) z", _Mul(_Add(x, y), z)), + (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), + (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), + (r"\left[x + y\right] z", _Mul(_Add(x, y), z)), + (r"\left\{x + y\right\} z", _Mul(_Add(x, y), z)), + (r"1+1", _Add(1, 1)), + (r"0+1", _Add(0, 1)), + (r"1*2", _Mul(1, 2)), + (r"0*1", _Mul(0, 1)), + (r"1 \times 2 ", _Mul(1, 2)), + (r"x = y", Eq(x, y)), + (r"x \neq y", Ne(x, y)), + (r"x < y", Lt(x, y)), + (r"x > y", Gt(x, y)), + (r"x \leq y", Le(x, y)), + (r"x \geq y", Ge(x, y)), + (r"x \le y", Le(x, y)), + (r"x \ge y", Ge(x, y)), + (r"\lfloor x \rfloor", floor(x)), + (r"\lceil x \rceil", ceiling(x)), + (r"\langle x |", Bra('x')), + (r"| x \rangle", Ket('x')), + (r"\sin \theta", sin(theta)), + (r"\sin(\theta)", sin(theta)), + (r"\sin^{-1} a", asin(a)), + (r"\sin a \cos b", _Mul(sin(a), cos(b))), + (r"\sin \cos \theta", sin(cos(theta))), + (r"\sin(\cos \theta)", sin(cos(theta))), + (r"\frac{a}{b}", a / b), + (r"\dfrac{a}{b}", a / b), + (r"\tfrac{a}{b}", a / b), + (r"\frac12", _Pow(2, -1)), + (r"\frac12y", _Mul(_Pow(2, -1), y)), + (r"\frac1234", _Mul(_Pow(2, -1), 34)), + (r"\frac2{3}", _Mul(2, _Pow(3, -1))), + (r"\frac{\sin{x}}2", _Mul(sin(x), _Pow(2, -1))), + (r"\frac{a + b}{c}", _Mul(a + b, _Pow(c, -1))), + (r"\frac{7}{3}", _Mul(7, _Pow(3, -1))), + (r"(\csc x)(\sec y)", csc(x)*sec(y)), + (r"\lim_{x \to 3} a", Limit(a, x, 3, dir='+-')), + (r"\lim_{x \rightarrow 3} a", Limit(a, x, 3, dir='+-')), + (r"\lim_{x \Rightarrow 3} a", Limit(a, x, 3, dir='+-')), + (r"\lim_{x \longrightarrow 3} a", Limit(a, x, 3, dir='+-')), + (r"\lim_{x \Longrightarrow 3} a", Limit(a, x, 3, dir='+-')), + (r"\lim_{x \to 3^{+}} a", Limit(a, x, 3, dir='+')), + (r"\lim_{x \to 3^{-}} a", Limit(a, x, 3, dir='-')), + (r"\lim_{x \to 3^+} a", Limit(a, x, 3, dir='+')), + (r"\lim_{x \to 3^-} a", Limit(a, x, 3, dir='-')), + (r"\infty", oo), + (r"\lim_{x \to \infty} \frac{1}{x}", Limit(_Pow(x, -1), x, oo)), + (r"\frac{d}{dx} x", Derivative(x, x)), + (r"\frac{d}{dt} x", Derivative(x, t)), + (r"f(x)", f(x)), + (r"f(x, y)", f(x, y)), + (r"f(x, y, z)", f(x, y, z)), + (r"f'_1(x)", Function("f_{1}'")(x)), + (r"f_{1}''(x+y)", Function("f_{1}''")(x+y)), + (r"\frac{d f(x)}{dx}", Derivative(f(x), x)), + (r"\frac{d\theta(x)}{dx}", Derivative(Function('theta')(x), x)), + (r"x \neq y", Unequality(x, y)), + (r"|x|", _Abs(x)), + (r"||x||", _Abs(Abs(x))), + (r"|x||y|", _Abs(x)*_Abs(y)), + (r"||x||y||", _Abs(_Abs(x)*_Abs(y))), + (r"\pi^{|xy|}", Symbol('pi')**_Abs(x*y)), + (r"\int x dx", Integral(x, x)), + (r"\int x d\theta", Integral(x, theta)), + (r"\int (x^2 - y)dx", Integral(x**2 - y, x)), + (r"\int x + a dx", Integral(_Add(x, a), x)), + (r"\int da", Integral(1, a)), + (r"\int_0^7 dx", Integral(1, (x, 0, 7))), + (r"\int\limits_{0}^{1} x dx", Integral(x, (x, 0, 1))), + (r"\int_a^b x dx", Integral(x, (x, a, b))), + (r"\int^b_a x dx", Integral(x, (x, a, b))), + (r"\int_{a}^b x dx", Integral(x, (x, a, b))), + (r"\int^{b}_a x dx", Integral(x, (x, a, b))), + (r"\int_{a}^{b} x dx", Integral(x, (x, a, b))), + (r"\int^{b}_{a} x dx", Integral(x, (x, a, b))), + (r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))), + (r"\int (x+a)", Integral(_Add(x, a), x)), + (r"\int a + b + c dx", Integral(_Add(_Add(a, b), c), x)), + (r"\int \frac{dz}{z}", Integral(Pow(z, -1), z)), + (r"\int \frac{3 dz}{z}", Integral(3*Pow(z, -1), z)), + (r"\int \frac{1}{x} dx", Integral(Pow(x, -1), x)), + (r"\int \frac{1}{a} + \frac{1}{b} dx", + Integral(_Add(_Pow(a, -1), Pow(b, -1)), x)), + (r"\int \frac{3 \cdot d\theta}{\theta}", + Integral(3*_Pow(theta, -1), theta)), + (r"\int \frac{1}{x} + 1 dx", Integral(_Add(_Pow(x, -1), 1), x)), + (r"x_0", Symbol('x_{0}')), + (r"x_{1}", Symbol('x_{1}')), + (r"x_a", Symbol('x_{a}')), + (r"x_{b}", Symbol('x_{b}')), + (r"h_\theta", Symbol('h_{theta}')), + (r"h_{\theta}", Symbol('h_{theta}')), + (r"h_{\theta}(x_0, x_1)", + Function('h_{theta}')(Symbol('x_{0}'), Symbol('x_{1}'))), + (r"x!", _factorial(x)), + (r"100!", _factorial(100)), + (r"\theta!", _factorial(theta)), + (r"(x + 1)!", _factorial(_Add(x, 1))), + (r"(x!)!", _factorial(_factorial(x))), + (r"x!!!", _factorial(_factorial(_factorial(x)))), + (r"5!7!", _Mul(_factorial(5), _factorial(7))), + (r"\sqrt{x}", sqrt(x)), + (r"\sqrt{x + b}", sqrt(_Add(x, b))), + (r"\sqrt[3]{\sin x}", root(sin(x), 3)), + (r"\sqrt[y]{\sin x}", root(sin(x), y)), + (r"\sqrt[\theta]{\sin x}", root(sin(x), theta)), + (r"\sqrt{\frac{12}{6}}", _Sqrt(_Mul(12, _Pow(6, -1)))), + (r"\overline{z}", _Conjugate(z)), + (r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))), + (r"\overline{x + y}", _Conjugate(_Add(x, y))), + (r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)), + (r"x < y", StrictLessThan(x, y)), + (r"x \leq y", LessThan(x, y)), + (r"x > y", StrictGreaterThan(x, y)), + (r"x \geq y", GreaterThan(x, y)), + (r"\mathit{x}", Symbol('x')), + (r"\mathit{test}", Symbol('test')), + (r"\mathit{TEST}", Symbol('TEST')), + (r"\mathit{HELLO world}", Symbol('HELLO world')), + (r"\sum_{k = 1}^{3} c", Sum(c, (k, 1, 3))), + (r"\sum_{k = 1}^3 c", Sum(c, (k, 1, 3))), + (r"\sum^{3}_{k = 1} c", Sum(c, (k, 1, 3))), + (r"\sum^3_{k = 1} c", Sum(c, (k, 1, 3))), + (r"\sum_{k = 1}^{10} k^2", Sum(k**2, (k, 1, 10))), + (r"\sum_{n = 0}^{\infty} \frac{1}{n!}", + Sum(_Pow(_factorial(n), -1), (n, 0, oo))), + (r"\prod_{a = b}^{c} x", Product(x, (a, b, c))), + (r"\prod_{a = b}^c x", Product(x, (a, b, c))), + (r"\prod^{c}_{a = b} x", Product(x, (a, b, c))), + (r"\prod^c_{a = b} x", Product(x, (a, b, c))), + (r"\exp x", _exp(x)), + (r"\exp(x)", _exp(x)), + (r"\lg x", _log(x, 10)), + (r"\ln x", _log(x, E)), + (r"\ln xy", _log(x*y, E)), + (r"\log x", _log(x, E)), + (r"\log xy", _log(x*y, E)), + (r"\log_{2} x", _log(x, 2)), + (r"\log_{a} x", _log(x, a)), + (r"\log_{11} x", _log(x, 11)), + (r"\log_{a^2} x", _log(x, _Pow(a, 2))), + (r"[x]", x), + (r"[a + b]", _Add(a, b)), + (r"\frac{d}{dx} [ \tan x ]", Derivative(tan(x), x)), + (r"\binom{n}{k}", _binomial(n, k)), + (r"\tbinom{n}{k}", _binomial(n, k)), + (r"\dbinom{n}{k}", _binomial(n, k)), + (r"\binom{n}{0}", _binomial(n, 0)), + (r"x^\binom{n}{k}", _Pow(x, _binomial(n, k))), + (r"a \, b", _Mul(a, b)), + (r"a \thinspace b", _Mul(a, b)), + (r"a \: b", _Mul(a, b)), + (r"a \medspace b", _Mul(a, b)), + (r"a \; b", _Mul(a, b)), + (r"a \thickspace b", _Mul(a, b)), + (r"a \quad b", _Mul(a, b)), + (r"a \qquad b", _Mul(a, b)), + (r"a \! b", _Mul(a, b)), + (r"a \negthinspace b", _Mul(a, b)), + (r"a \negmedspace b", _Mul(a, b)), + (r"a \negthickspace b", _Mul(a, b)), + (r"\int x \, dx", Integral(x, x)), + (r"\log_2 x", _log(x, 2)), + (r"\log_a x", _log(x, a)), + (r"5^0 - 4^0", _Add(_Pow(5, 0), _Mul(-1, _Pow(4, 0)))), + (r"3x - 1", _Add(_Mul(3, x), -1)) +] + + +def test_parseable(): + from sympy.parsing.latex import parse_latex + for latex_str, sympy_expr in GOOD_PAIRS: + assert parse_latex(latex_str) == sympy_expr, latex_str + +# These bad LaTeX strings should raise a LaTeXParsingError when parsed +BAD_STRINGS = [ + r"(", + r")", + r"\frac{d}{dx}", + r"(\frac{d}{dx})", + r"\sqrt{}", + r"\sqrt", + r"\overline{}", + r"\overline", + r"{", + r"}", + r"\mathit{x + y}", + r"\mathit{21}", + r"\frac{2}{}", + r"\frac{}{2}", + r"\int", + r"!", + r"!0", + r"_", + r"^", + r"|", + r"||x|", + r"()", + r"((((((((((((((((()))))))))))))))))", + r"-", + r"\frac{d}{dx} + \frac{d}{dt}", + r"f(x,,y)", + r"f(x,y,", + r"\sin^x", + r"\cos^2", + r"@", + r"#", + r"$", + r"%", + r"&", + r"*", + r"" "\\", + r"~", + r"\frac{(2 + x}{1 - x)}", +] + +def test_not_parseable(): + from sympy.parsing.latex import parse_latex, LaTeXParsingError + for latex_str in BAD_STRINGS: + with raises(LaTeXParsingError): + parse_latex(latex_str) + +# At time of migration from latex2sympy, should fail but doesn't +FAILING_BAD_STRINGS = [ + r"\cos 1 \cos", + r"f(,", + r"f()", + r"a \div \div b", + r"a \cdot \cdot b", + r"a // b", + r"a +", + r"1.1.1", + r"1 +", + r"a / b /", +] + +@XFAIL +def test_failing_not_parseable(): + from sympy.parsing.latex import parse_latex, LaTeXParsingError + for latex_str in FAILING_BAD_STRINGS: + with raises(LaTeXParsingError): + parse_latex(latex_str) + +# In strict mode, FAILING_BAD_STRINGS would fail +def test_strict_mode(): + from sympy.parsing.latex import parse_latex, LaTeXParsingError + for latex_str in FAILING_BAD_STRINGS: + with raises(LaTeXParsingError): + parse_latex(latex_str, strict=True) diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_latex_lark.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_latex_lark.py new file mode 100644 index 0000000000000000000000000000000000000000..da5b70f04380691125b87d58fc3a9ba96b8d7c21 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_latex_lark.py @@ -0,0 +1,595 @@ +from sympy.testing.pytest import XFAIL +from sympy.parsing.latex.lark import parse_latex_lark +from sympy.external import import_module + +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core.function import Derivative, Function +from sympy.core.numbers import E, oo, Rational +from sympy.core.power import Pow +from sympy.core.parameters import evaluate +from sympy.core.relational import GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Unequality +from sympy.core.symbol import Symbol +from sympy.functions.combinatorial.factorials import binomial, factorial +from sympy.functions.elementary.complexes import Abs, conjugate +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.integers import ceiling, floor +from sympy.functions.elementary.miscellaneous import root, sqrt, Min, Max +from sympy.functions.elementary.trigonometric import asin, cos, csc, sec, sin, tan +from sympy.integrals.integrals import Integral +from sympy.series.limits import Limit + +from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge +from sympy.physics.quantum import Bra, Ket, InnerProduct +from sympy.abc import x, y, z, a, b, c, d, t, k, n + +from .test_latex import theta, f, _Add, _Mul, _Pow, _Sqrt, _Conjugate, _Abs, _factorial, _exp, _binomial + +lark = import_module("lark") + +# disable tests if lark is not present +disabled = lark is None + +# shorthand definitions that are only needed for the Lark LaTeX parser +def _Min(*args): + return Min(*args, evaluate=False) + + +def _Max(*args): + return Max(*args, evaluate=False) + + +def _log(a, b=E): + if b == E: + return log(a, evaluate=False) + else: + return log(a, b, evaluate=False) + + +# These LaTeX strings should parse to the corresponding SymPy expression +SYMBOL_EXPRESSION_PAIRS = [ + (r"x_0", Symbol('x_{0}')), + (r"x_{1}", Symbol('x_{1}')), + (r"x_a", Symbol('x_{a}')), + (r"x_{b}", Symbol('x_{b}')), + (r"h_\theta", Symbol('h_{theta}')), + (r"h_{\theta}", Symbol('h_{theta}')), + (r"y''_1", Symbol("y_{1}''")), + (r"y_1''", Symbol("y_{1}''")), + (r"\mathit{x}", Symbol('x')), + (r"\mathit{test}", Symbol('test')), + (r"\mathit{TEST}", Symbol('TEST')), + (r"\mathit{HELLO world}", Symbol('HELLO world')) +] + +UNEVALUATED_SIMPLE_EXPRESSION_PAIRS = [ + (r"0", 0), + (r"1", 1), + (r"-3.14", -3.14), + (r"(-7.13)(1.5)", _Mul(-7.13, 1.5)), + (r"1+1", _Add(1, 1)), + (r"0+1", _Add(0, 1)), + (r"1*2", _Mul(1, 2)), + (r"0*1", _Mul(0, 1)), + (r"x", x), + (r"2x", 2 * x), + (r"3x - 1", _Add(_Mul(3, x), -1)), + (r"-c", -c), + (r"\infty", oo), + (r"a \cdot b", a * b), + (r"1 \times 2 ", _Mul(1, 2)), + (r"a / b", a / b), + (r"a \div b", a / b), + (r"a + b", a + b), + (r"a + b - a", _Add(a + b, -a)), + (r"(x + y) z", _Mul(_Add(x, y), z)), + (r"a'b+ab'", _Add(_Mul(Symbol("a'"), b), _Mul(a, Symbol("b'")))) +] + +EVALUATED_SIMPLE_EXPRESSION_PAIRS = [ + (r"(-7.13)(1.5)", -10.695), + (r"1+1", 2), + (r"0+1", 1), + (r"1*2", 2), + (r"0*1", 0), + (r"2x", 2 * x), + (r"3x - 1", 3 * x - 1), + (r"-c", -c), + (r"a \cdot b", a * b), + (r"1 \times 2 ", 2), + (r"a / b", a / b), + (r"a \div b", a / b), + (r"a + b", a + b), + (r"a + b - a", b), + (r"(x + y) z", (x + y) * z), +] + +UNEVALUATED_FRACTION_EXPRESSION_PAIRS = [ + (r"\frac{a}{b}", a / b), + (r"\dfrac{a}{b}", a / b), + (r"\tfrac{a}{b}", a / b), + (r"\frac12", _Mul(1, _Pow(2, -1))), + (r"\frac12y", _Mul(_Mul(1, _Pow(2, -1)), y)), + (r"\frac1234", _Mul(_Mul(1, _Pow(2, -1)), 34)), + (r"\frac2{3}", _Mul(2, _Pow(3, -1))), + (r"\frac{a + b}{c}", _Mul(a + b, _Pow(c, -1))), + (r"\frac{7}{3}", _Mul(7, _Pow(3, -1))) +] + +EVALUATED_FRACTION_EXPRESSION_PAIRS = [ + (r"\frac{a}{b}", a / b), + (r"\dfrac{a}{b}", a / b), + (r"\tfrac{a}{b}", a / b), + (r"\frac12", Rational(1, 2)), + (r"\frac12y", y / 2), + (r"\frac1234", 17), + (r"\frac2{3}", Rational(2, 3)), + (r"\frac{a + b}{c}", (a + b) / c), + (r"\frac{7}{3}", Rational(7, 3)) +] + +RELATION_EXPRESSION_PAIRS = [ + (r"x = y", Eq(x, y)), + (r"x \neq y", Ne(x, y)), + (r"x < y", Lt(x, y)), + (r"x > y", Gt(x, y)), + (r"x \leq y", Le(x, y)), + (r"x \geq y", Ge(x, y)), + (r"x \le y", Le(x, y)), + (r"x \ge y", Ge(x, y)), + (r"x < y", StrictLessThan(x, y)), + (r"x \leq y", LessThan(x, y)), + (r"x > y", StrictGreaterThan(x, y)), + (r"x \geq y", GreaterThan(x, y)), + (r"x \neq y", Unequality(x, y)), # same as 2nd one in the list + (r"a^2 + b^2 = c^2", Eq(a**2 + b**2, c**2)) +] + +UNEVALUATED_POWER_EXPRESSION_PAIRS = [ + (r"x^2", x ** 2), + (r"x^\frac{1}{2}", _Pow(x, _Mul(1, _Pow(2, -1)))), + (r"x^{3 + 1}", x ** _Add(3, 1)), + (r"\pi^{|xy|}", Symbol('pi') ** _Abs(x * y)), + (r"5^0 - 4^0", _Add(_Pow(5, 0), _Mul(-1, _Pow(4, 0)))) +] + +EVALUATED_POWER_EXPRESSION_PAIRS = [ + (r"x^2", x ** 2), + (r"x^\frac{1}{2}", sqrt(x)), + (r"x^{3 + 1}", x ** 4), + (r"\pi^{|xy|}", Symbol('pi') ** _Abs(x * y)), + (r"5^0 - 4^0", 0) +] + +UNEVALUATED_INTEGRAL_EXPRESSION_PAIRS = [ + (r"\int x dx", Integral(_Mul(1, x), x)), + (r"\int x \, dx", Integral(_Mul(1, x), x)), + (r"\int x d\theta", Integral(_Mul(1, x), theta)), + (r"\int (x^2 - y)dx", Integral(_Mul(1, x ** 2 - y), x)), + (r"\int x + a dx", Integral(_Mul(1, _Add(x, a)), x)), + (r"\int da", Integral(_Mul(1, 1), a)), + (r"\int_0^7 dx", Integral(_Mul(1, 1), (x, 0, 7))), + (r"\int\limits_{0}^{1} x dx", Integral(_Mul(1, x), (x, 0, 1))), + (r"\int_a^b x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int^b_a x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int_{a}^b x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int^{b}_a x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int_{a}^{b} x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int^{b}_{a} x dx", Integral(_Mul(1, x), (x, a, b))), + (r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))), + (r"\int a + b + c dx", Integral(_Mul(1, _Add(_Add(a, b), c)), x)), + (r"\int \frac{dz}{z}", Integral(_Mul(1, _Mul(1, Pow(z, -1))), z)), + (r"\int \frac{3 dz}{z}", Integral(_Mul(1, _Mul(3, _Pow(z, -1))), z)), + (r"\int \frac{1}{x} dx", Integral(_Mul(1, _Mul(1, Pow(x, -1))), x)), + (r"\int \frac{1}{a} + \frac{1}{b} dx", + Integral(_Mul(1, _Add(_Mul(1, _Pow(a, -1)), _Mul(1, Pow(b, -1)))), x)), + (r"\int \frac{1}{x} + 1 dx", Integral(_Mul(1, _Add(_Mul(1, _Pow(x, -1)), 1)), x)) +] + +EVALUATED_INTEGRAL_EXPRESSION_PAIRS = [ + (r"\int x dx", Integral(x, x)), + (r"\int x \, dx", Integral(x, x)), + (r"\int x d\theta", Integral(x, theta)), + (r"\int (x^2 - y)dx", Integral(x ** 2 - y, x)), + (r"\int x + a dx", Integral(x + a, x)), + (r"\int da", Integral(1, a)), + (r"\int_0^7 dx", Integral(1, (x, 0, 7))), + (r"\int\limits_{0}^{1} x dx", Integral(x, (x, 0, 1))), + (r"\int_a^b x dx", Integral(x, (x, a, b))), + (r"\int^b_a x dx", Integral(x, (x, a, b))), + (r"\int_{a}^b x dx", Integral(x, (x, a, b))), + (r"\int^{b}_a x dx", Integral(x, (x, a, b))), + (r"\int_{a}^{b} x dx", Integral(x, (x, a, b))), + (r"\int^{b}_{a} x dx", Integral(x, (x, a, b))), + (r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))), + (r"\int a + b + c dx", Integral(a + b + c, x)), + (r"\int \frac{dz}{z}", Integral(Pow(z, -1), z)), + (r"\int \frac{3 dz}{z}", Integral(3 * Pow(z, -1), z)), + (r"\int \frac{1}{x} dx", Integral(1 / x, x)), + (r"\int \frac{1}{a} + \frac{1}{b} dx", Integral(1 / a + 1 / b, x)), + (r"\int \frac{1}{x} + 1 dx", Integral(1 / x + 1, x)) +] + +DERIVATIVE_EXPRESSION_PAIRS = [ + (r"\frac{d}{dx} x", Derivative(x, x)), + (r"\frac{d}{dt} x", Derivative(x, t)), + (r"\frac{d}{dx} ( \tan x )", Derivative(tan(x), x)), + (r"\frac{d f(x)}{dx}", Derivative(f(x), x)), + (r"\frac{d\theta(x)}{dx}", Derivative(Function('theta')(x), x)) +] + +TRIGONOMETRIC_EXPRESSION_PAIRS = [ + (r"\sin \theta", sin(theta)), + (r"\sin(\theta)", sin(theta)), + (r"\sin^{-1} a", asin(a)), + (r"\sin a \cos b", _Mul(sin(a), cos(b))), + (r"\sin \cos \theta", sin(cos(theta))), + (r"\sin(\cos \theta)", sin(cos(theta))), + (r"(\csc x)(\sec y)", csc(x) * sec(y)), + (r"\frac{\sin{x}}2", _Mul(sin(x), _Pow(2, -1))) +] + +UNEVALUATED_LIMIT_EXPRESSION_PAIRS = [ + (r"\lim_{x \to 3} a", Limit(a, x, 3, dir="+-")), + (r"\lim_{x \rightarrow 3} a", Limit(a, x, 3, dir="+-")), + (r"\lim_{x \Rightarrow 3} a", Limit(a, x, 3, dir="+-")), + (r"\lim_{x \longrightarrow 3} a", Limit(a, x, 3, dir="+-")), + (r"\lim_{x \Longrightarrow 3} a", Limit(a, x, 3, dir="+-")), + (r"\lim_{x \to 3^{+}} a", Limit(a, x, 3, dir="+")), + (r"\lim_{x \to 3^{-}} a", Limit(a, x, 3, dir="-")), + (r"\lim_{x \to 3^+} a", Limit(a, x, 3, dir="+")), + (r"\lim_{x \to 3^-} a", Limit(a, x, 3, dir="-")), + (r"\lim_{x \to \infty} \frac{1}{x}", Limit(_Mul(1, _Pow(x, -1)), x, oo)) +] + +EVALUATED_LIMIT_EXPRESSION_PAIRS = [ + (r"\lim_{x \to \infty} \frac{1}{x}", Limit(1 / x, x, oo)) +] + +UNEVALUATED_SQRT_EXPRESSION_PAIRS = [ + (r"\sqrt{x}", sqrt(x)), + (r"\sqrt{x + b}", sqrt(_Add(x, b))), + (r"\sqrt[3]{\sin x}", _Pow(sin(x), _Pow(3, -1))), + # the above test needed to be handled differently than the ones below because root + # acts differently if its second argument is a number + (r"\sqrt[y]{\sin x}", root(sin(x), y)), + (r"\sqrt[\theta]{\sin x}", root(sin(x), theta)), + (r"\sqrt{\frac{12}{6}}", _Sqrt(_Mul(12, _Pow(6, -1)))) +] + +EVALUATED_SQRT_EXPRESSION_PAIRS = [ + (r"\sqrt{x}", sqrt(x)), + (r"\sqrt{x + b}", sqrt(x + b)), + (r"\sqrt[3]{\sin x}", root(sin(x), 3)), + (r"\sqrt[y]{\sin x}", root(sin(x), y)), + (r"\sqrt[\theta]{\sin x}", root(sin(x), theta)), + (r"\sqrt{\frac{12}{6}}", sqrt(2)) +] + +UNEVALUATED_FACTORIAL_EXPRESSION_PAIRS = [ + (r"x!", _factorial(x)), + (r"100!", _factorial(100)), + (r"\theta!", _factorial(theta)), + (r"(x + 1)!", _factorial(_Add(x, 1))), + (r"(x!)!", _factorial(_factorial(x))), + (r"x!!!", _factorial(_factorial(_factorial(x)))), + (r"5!7!", _Mul(_factorial(5), _factorial(7))) +] + +EVALUATED_FACTORIAL_EXPRESSION_PAIRS = [ + (r"x!", factorial(x)), + (r"100!", factorial(100)), + (r"\theta!", factorial(theta)), + (r"(x + 1)!", factorial(x + 1)), + (r"(x!)!", factorial(factorial(x))), + (r"x!!!", factorial(factorial(factorial(x)))), + (r"5!7!", factorial(5) * factorial(7)) +] + +UNEVALUATED_SUM_EXPRESSION_PAIRS = [ + (r"\sum_{k = 1}^{3} c", Sum(_Mul(1, c), (k, 1, 3))), + (r"\sum_{k = 1}^3 c", Sum(_Mul(1, c), (k, 1, 3))), + (r"\sum^{3}_{k = 1} c", Sum(_Mul(1, c), (k, 1, 3))), + (r"\sum^3_{k = 1} c", Sum(_Mul(1, c), (k, 1, 3))), + (r"\sum_{k = 1}^{10} k^2", Sum(_Mul(1, k ** 2), (k, 1, 10))), + (r"\sum_{n = 0}^{\infty} \frac{1}{n!}", + Sum(_Mul(1, _Mul(1, _Pow(_factorial(n), -1))), (n, 0, oo))) +] + +EVALUATED_SUM_EXPRESSION_PAIRS = [ + (r"\sum_{k = 1}^{3} c", Sum(c, (k, 1, 3))), + (r"\sum_{k = 1}^3 c", Sum(c, (k, 1, 3))), + (r"\sum^{3}_{k = 1} c", Sum(c, (k, 1, 3))), + (r"\sum^3_{k = 1} c", Sum(c, (k, 1, 3))), + (r"\sum_{k = 1}^{10} k^2", Sum(k ** 2, (k, 1, 10))), + (r"\sum_{n = 0}^{\infty} \frac{1}{n!}", Sum(1 / factorial(n), (n, 0, oo))) +] + +UNEVALUATED_PRODUCT_EXPRESSION_PAIRS = [ + (r"\prod_{a = b}^{c} x", Product(x, (a, b, c))), + (r"\prod_{a = b}^c x", Product(x, (a, b, c))), + (r"\prod^{c}_{a = b} x", Product(x, (a, b, c))), + (r"\prod^c_{a = b} x", Product(x, (a, b, c))) +] + +APPLIED_FUNCTION_EXPRESSION_PAIRS = [ + (r"f(x)", f(x)), + (r"f(x, y)", f(x, y)), + (r"f(x, y, z)", f(x, y, z)), + (r"f'_1(x)", Function("f_{1}'")(x)), + (r"f_{1}''(x+y)", Function("f_{1}''")(x + y)), + (r"h_{\theta}(x_0, x_1)", + Function('h_{theta}')(Symbol('x_{0}'), Symbol('x_{1}'))) +] + +UNEVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS = [ + (r"|x|", _Abs(x)), + (r"||x||", _Abs(Abs(x))), + (r"|x||y|", _Abs(x) * _Abs(y)), + (r"||x||y||", _Abs(_Abs(x) * _Abs(y))), + (r"\lfloor x \rfloor", floor(x)), + (r"\lceil x \rceil", ceiling(x)), + (r"\exp x", _exp(x)), + (r"\exp(x)", _exp(x)), + (r"\lg x", _log(x, 10)), + (r"\ln x", _log(x)), + (r"\ln xy", _log(x * y)), + (r"\log x", _log(x)), + (r"\log xy", _log(x * y)), + (r"\log_{2} x", _log(x, 2)), + (r"\log_{a} x", _log(x, a)), + (r"\log_{11} x", _log(x, 11)), + (r"\log_{a^2} x", _log(x, _Pow(a, 2))), + (r"\log_2 x", _log(x, 2)), + (r"\log_a x", _log(x, a)), + (r"\overline{z}", _Conjugate(z)), + (r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))), + (r"\overline{x + y}", _Conjugate(_Add(x, y))), + (r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)), + (r"\min(a, b)", _Min(a, b)), + (r"\min(a, b, c - d, xy)", _Min(a, b, c - d, x * y)), + (r"\max(a, b)", _Max(a, b)), + (r"\max(a, b, c - d, xy)", _Max(a, b, c - d, x * y)), + # physics things don't have an `evaluate=False` variant + (r"\langle x |", Bra('x')), + (r"| x \rangle", Ket('x')), + (r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))), +] + +EVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS = [ + (r"|x|", Abs(x)), + (r"||x||", Abs(Abs(x))), + (r"|x||y|", Abs(x) * Abs(y)), + (r"||x||y||", Abs(Abs(x) * Abs(y))), + (r"\lfloor x \rfloor", floor(x)), + (r"\lceil x \rceil", ceiling(x)), + (r"\exp x", exp(x)), + (r"\exp(x)", exp(x)), + (r"\lg x", log(x, 10)), + (r"\ln x", log(x)), + (r"\ln xy", log(x * y)), + (r"\log x", log(x)), + (r"\log xy", log(x * y)), + (r"\log_{2} x", log(x, 2)), + (r"\log_{a} x", log(x, a)), + (r"\log_{11} x", log(x, 11)), + (r"\log_{a^2} x", log(x, _Pow(a, 2))), + (r"\log_2 x", log(x, 2)), + (r"\log_a x", log(x, a)), + (r"\overline{z}", conjugate(z)), + (r"\overline{\overline{z}}", conjugate(conjugate(z))), + (r"\overline{x + y}", conjugate(x + y)), + (r"\overline{x} + \overline{y}", conjugate(x) + conjugate(y)), + (r"\min(a, b)", Min(a, b)), + (r"\min(a, b, c - d, xy)", Min(a, b, c - d, x * y)), + (r"\max(a, b)", Max(a, b)), + (r"\max(a, b, c - d, xy)", Max(a, b, c - d, x * y)), + (r"\langle x |", Bra('x')), + (r"| x \rangle", Ket('x')), + (r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))), +] + +SPACING_RELATED_EXPRESSION_PAIRS = [ + (r"a \, b", _Mul(a, b)), + (r"a \thinspace b", _Mul(a, b)), + (r"a \: b", _Mul(a, b)), + (r"a \medspace b", _Mul(a, b)), + (r"a \; b", _Mul(a, b)), + (r"a \thickspace b", _Mul(a, b)), + (r"a \quad b", _Mul(a, b)), + (r"a \qquad b", _Mul(a, b)), + (r"a \! b", _Mul(a, b)), + (r"a \negthinspace b", _Mul(a, b)), + (r"a \negmedspace b", _Mul(a, b)), + (r"a \negthickspace b", _Mul(a, b)) +] + +UNEVALUATED_BINOMIAL_EXPRESSION_PAIRS = [ + (r"\binom{n}{k}", _binomial(n, k)), + (r"\tbinom{n}{k}", _binomial(n, k)), + (r"\dbinom{n}{k}", _binomial(n, k)), + (r"\binom{n}{0}", _binomial(n, 0)), + (r"x^\binom{n}{k}", _Pow(x, _binomial(n, k))) +] + +EVALUATED_BINOMIAL_EXPRESSION_PAIRS = [ + (r"\binom{n}{k}", binomial(n, k)), + (r"\tbinom{n}{k}", binomial(n, k)), + (r"\dbinom{n}{k}", binomial(n, k)), + (r"\binom{n}{0}", binomial(n, 0)), + (r"x^\binom{n}{k}", x ** binomial(n, k)) +] + +MISCELLANEOUS_EXPRESSION_PAIRS = [ + (r"\left(x + y\right) z", _Mul(_Add(x, y), z)), + (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), + (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), +] + + +def test_symbol_expressions(): + expected_failures = {6, 7} + for i, (latex_str, sympy_expr) in enumerate(SYMBOL_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_simple_expressions(): + expected_failures = {20} + for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_SIMPLE_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for i, (latex_str, sympy_expr) in enumerate(EVALUATED_SIMPLE_EXPRESSION_PAIRS): + if i in expected_failures: + continue + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_fraction_expressions(): + for latex_str, sympy_expr in UNEVALUATED_FRACTION_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_FRACTION_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_relation_expressions(): + for latex_str, sympy_expr in RELATION_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + +def test_power_expressions(): + expected_failures = {3} + for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_POWER_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for i, (latex_str, sympy_expr) in enumerate(EVALUATED_POWER_EXPRESSION_PAIRS): + if i in expected_failures: + continue + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_integral_expressions(): + expected_failures = {14} + for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_INTEGRAL_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, i + + for i, (latex_str, sympy_expr) in enumerate(EVALUATED_INTEGRAL_EXPRESSION_PAIRS): + if i in expected_failures: + continue + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_derivative_expressions(): + expected_failures = {3, 4} + for i, (latex_str, sympy_expr) in enumerate(DERIVATIVE_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for i, (latex_str, sympy_expr) in enumerate(DERIVATIVE_EXPRESSION_PAIRS): + if i in expected_failures: + continue + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_trigonometric_expressions(): + expected_failures = {3} + for i, (latex_str, sympy_expr) in enumerate(TRIGONOMETRIC_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_limit_expressions(): + for latex_str, sympy_expr in UNEVALUATED_LIMIT_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_square_root_expressions(): + for latex_str, sympy_expr in UNEVALUATED_SQRT_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_SQRT_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_factorial_expressions(): + for latex_str, sympy_expr in UNEVALUATED_FACTORIAL_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_FACTORIAL_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_sum_expressions(): + for latex_str, sympy_expr in UNEVALUATED_SUM_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_SUM_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_product_expressions(): + for latex_str, sympy_expr in UNEVALUATED_PRODUCT_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + +@XFAIL +def test_applied_function_expressions(): + expected_failures = {0, 3, 4} # 0 is ambiguous, and the others require not-yet-added features + # not sure why 1, and 2 are failing + for i, (latex_str, sympy_expr) in enumerate(APPLIED_FUNCTION_EXPRESSION_PAIRS): + if i in expected_failures: + continue + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_common_function_expressions(): + for latex_str, sympy_expr in UNEVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + +# unhandled bug causing these to fail +@XFAIL +def test_spacing(): + for latex_str, sympy_expr in SPACING_RELATED_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_binomial_expressions(): + for latex_str, sympy_expr in UNEVALUATED_BINOMIAL_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + for latex_str, sympy_expr in EVALUATED_BINOMIAL_EXPRESSION_PAIRS: + assert parse_latex_lark(latex_str) == sympy_expr, latex_str + + +def test_miscellaneous_expressions(): + for latex_str, sympy_expr in MISCELLANEOUS_EXPRESSION_PAIRS: + with evaluate(False): + assert parse_latex_lark(latex_str) == sympy_expr, latex_str diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_mathematica.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_mathematica.py new file mode 100644 index 0000000000000000000000000000000000000000..df193b6d61f9c82778d8e0a40b893cbe6cb8f06a --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_mathematica.py @@ -0,0 +1,280 @@ +from sympy import sin, Function, symbols, Dummy, Lambda, cos +from sympy.parsing.mathematica import parse_mathematica, MathematicaParser +from sympy.core.sympify import sympify +from sympy.abc import n, w, x, y, z +from sympy.testing.pytest import raises + + +def test_mathematica(): + d = { + '- 6x': '-6*x', + 'Sin[x]^2': 'sin(x)**2', + '2(x-1)': '2*(x-1)', + '3y+8': '3*y+8', + 'ArcSin[2x+9(4-x)^2]/x': 'asin(2*x+9*(4-x)**2)/x', + 'x+y': 'x+y', + '355/113': '355/113', + '2.718281828': '2.718281828', + 'Cos(1/2 * π)': 'Cos(π/2)', + 'Sin[12]': 'sin(12)', + 'Exp[Log[4]]': 'exp(log(4))', + '(x+1)(x+3)': '(x+1)*(x+3)', + 'Cos[ArcCos[3.6]]': 'cos(acos(3.6))', + 'Cos[x]==Sin[y]': 'Eq(cos(x), sin(y))', + '2*Sin[x+y]': '2*sin(x+y)', + 'Sin[x]+Cos[y]': 'sin(x)+cos(y)', + 'Sin[Cos[x]]': 'sin(cos(x))', + '2*Sqrt[x+y]': '2*sqrt(x+y)', # Test case from the issue 4259 + '+Sqrt[2]': 'sqrt(2)', + '-Sqrt[2]': '-sqrt(2)', + '-1/Sqrt[2]': '-1/sqrt(2)', + '-(1/Sqrt[3])': '-(1/sqrt(3))', + '1/(2*Sqrt[5])': '1/(2*sqrt(5))', + 'Mod[5,3]': 'Mod(5,3)', + '-Mod[5,3]': '-Mod(5,3)', + '(x+1)y': '(x+1)*y', + 'x(y+1)': 'x*(y+1)', + 'Sin[x]Cos[y]': 'sin(x)*cos(y)', + 'Sin[x]^2Cos[y]^2': 'sin(x)**2*cos(y)**2', + 'Cos[x]^2(1 - Cos[y]^2)': 'cos(x)**2*(1-cos(y)**2)', + 'x y': 'x*y', + 'x y': 'x*y', + '2 x': '2*x', + 'x 8': 'x*8', + '2 8': '2*8', + '4.x': '4.*x', + '4. 3': '4.*3', + '4. 3.': '4.*3.', + '1 2 3': '1*2*3', + ' - 2 * Sqrt[ 2 3 * ( 1 + 5 ) ] ': '-2*sqrt(2*3*(1+5))', + 'Log[2,4]': 'log(4,2)', + 'Log[Log[2,4],4]': 'log(4,log(4,2))', + 'Exp[Sqrt[2]^2Log[2, 8]]': 'exp(sqrt(2)**2*log(8,2))', + 'ArcSin[Cos[0]]': 'asin(cos(0))', + 'Log2[16]': 'log(16,2)', + 'Max[1,-2,3,-4]': 'Max(1,-2,3,-4)', + 'Min[1,-2,3]': 'Min(1,-2,3)', + 'Exp[I Pi/2]': 'exp(I*pi/2)', + 'ArcTan[x,y]': 'atan2(y,x)', + 'Pochhammer[x,y]': 'rf(x,y)', + 'ExpIntegralEi[x]': 'Ei(x)', + 'SinIntegral[x]': 'Si(x)', + 'CosIntegral[x]': 'Ci(x)', + 'AiryAi[x]': 'airyai(x)', + 'AiryAiPrime[5]': 'airyaiprime(5)', + 'AiryBi[x]': 'airybi(x)', + 'AiryBiPrime[7]': 'airybiprime(7)', + 'LogIntegral[4]': ' li(4)', + 'PrimePi[7]': 'primepi(7)', + 'Prime[5]': 'prime(5)', + 'PrimeQ[5]': 'isprime(5)', + 'Rational[2,19]': 'Rational(2,19)', # test case for issue 25716 + } + + for e in d: + assert parse_mathematica(e) == sympify(d[e]) + + # The parsed form of this expression should not evaluate the Lambda object: + assert parse_mathematica("Sin[#]^2 + Cos[#]^2 &[x]") == sin(x)**2 + cos(x)**2 + + d1, d2, d3 = symbols("d1:4", cls=Dummy) + assert parse_mathematica("Sin[#] + Cos[#3] &").dummy_eq(Lambda((d1, d2, d3), sin(d1) + cos(d3))) + assert parse_mathematica("Sin[#^2] &").dummy_eq(Lambda(d1, sin(d1**2))) + assert parse_mathematica("Function[x, x^3]") == Lambda(x, x**3) + assert parse_mathematica("Function[{x, y}, x^2 + y^2]") == Lambda((x, y), x**2 + y**2) + + +def test_parser_mathematica_tokenizer(): + parser = MathematicaParser() + + chain = lambda expr: parser._from_tokens_to_fullformlist(parser._from_mathematica_to_tokens(expr)) + + # Basic patterns + assert chain("x") == "x" + assert chain("42") == "42" + assert chain(".2") == ".2" + assert chain("+x") == "x" + assert chain("-1") == "-1" + assert chain("- 3") == "-3" + assert chain("α") == "α" + assert chain("+Sin[x]") == ["Sin", "x"] + assert chain("-Sin[x]") == ["Times", "-1", ["Sin", "x"]] + assert chain("x(a+1)") == ["Times", "x", ["Plus", "a", "1"]] + assert chain("(x)") == "x" + assert chain("(+x)") == "x" + assert chain("-a") == ["Times", "-1", "a"] + assert chain("(-x)") == ["Times", "-1", "x"] + assert chain("(x + y)") == ["Plus", "x", "y"] + assert chain("3 + 4") == ["Plus", "3", "4"] + assert chain("a - 3") == ["Plus", "a", "-3"] + assert chain("a - b") == ["Plus", "a", ["Times", "-1", "b"]] + assert chain("7 * 8") == ["Times", "7", "8"] + assert chain("a + b*c") == ["Plus", "a", ["Times", "b", "c"]] + assert chain("a + b* c* d + 2 * e") == ["Plus", "a", ["Times", "b", "c", "d"], ["Times", "2", "e"]] + assert chain("a / b") == ["Times", "a", ["Power", "b", "-1"]] + + # Missing asterisk (*) patterns: + assert chain("x y") == ["Times", "x", "y"] + assert chain("3 4") == ["Times", "3", "4"] + assert chain("a[b] c") == ["Times", ["a", "b"], "c"] + assert chain("(x) (y)") == ["Times", "x", "y"] + assert chain("3 (a)") == ["Times", "3", "a"] + assert chain("(a) b") == ["Times", "a", "b"] + assert chain("4.2") == "4.2" + assert chain("4 2") == ["Times", "4", "2"] + assert chain("4 2") == ["Times", "4", "2"] + assert chain("3 . 4") == ["Dot", "3", "4"] + assert chain("4. 2") == ["Times", "4.", "2"] + assert chain("x.y") == ["Dot", "x", "y"] + assert chain("4.y") == ["Times", "4.", "y"] + assert chain("4 .y") == ["Dot", "4", "y"] + assert chain("x.4") == ["Times", "x", ".4"] + assert chain("x0.3") == ["Times", "x0", ".3"] + assert chain("x. 4") == ["Dot", "x", "4"] + + # Comments + assert chain("a (* +b *) + c") == ["Plus", "a", "c"] + assert chain("a (* + b *) + (**)c (* +d *) + e") == ["Plus", "a", "c", "e"] + assert chain("""a + (* + + b + *) c + (* d + *) e + """) == ["Plus", "a", "c", "e"] + + # Operators couples + and -, * and / are mutually associative: + # (i.e. expression gets flattened when mixing these operators) + assert chain("a*b/c") == ["Times", "a", "b", ["Power", "c", "-1"]] + assert chain("a/b*c") == ["Times", "a", ["Power", "b", "-1"], "c"] + assert chain("a+b-c") == ["Plus", "a", "b", ["Times", "-1", "c"]] + assert chain("a-b+c") == ["Plus", "a", ["Times", "-1", "b"], "c"] + assert chain("-a + b -c ") == ["Plus", ["Times", "-1", "a"], "b", ["Times", "-1", "c"]] + assert chain("a/b/c*d") == ["Times", "a", ["Power", "b", "-1"], ["Power", "c", "-1"], "d"] + assert chain("a/b/c") == ["Times", "a", ["Power", "b", "-1"], ["Power", "c", "-1"]] + assert chain("a-b-c") == ["Plus", "a", ["Times", "-1", "b"], ["Times", "-1", "c"]] + assert chain("1/a") == ["Times", "1", ["Power", "a", "-1"]] + assert chain("1/a/b") == ["Times", "1", ["Power", "a", "-1"], ["Power", "b", "-1"]] + assert chain("-1/a*b") == ["Times", "-1", ["Power", "a", "-1"], "b"] + + # Enclosures of various kinds, i.e. ( ) [ ] [[ ]] { } + assert chain("(a + b) + c") == ["Plus", ["Plus", "a", "b"], "c"] + assert chain(" a + (b + c) + d ") == ["Plus", "a", ["Plus", "b", "c"], "d"] + assert chain("a * (b + c)") == ["Times", "a", ["Plus", "b", "c"]] + assert chain("a b (c d)") == ["Times", "a", "b", ["Times", "c", "d"]] + assert chain("{a, b, 2, c}") == ["List", "a", "b", "2", "c"] + assert chain("{a, {b, c}}") == ["List", "a", ["List", "b", "c"]] + assert chain("{{a}}") == ["List", ["List", "a"]] + assert chain("a[b, c]") == ["a", "b", "c"] + assert chain("a[[b, c]]") == ["Part", "a", "b", "c"] + assert chain("a[b[c]]") == ["a", ["b", "c"]] + assert chain("a[[b, c[[d, {e,f}]]]]") == ["Part", "a", "b", ["Part", "c", "d", ["List", "e", "f"]]] + assert chain("a[b[[c,d]]]") == ["a", ["Part", "b", "c", "d"]] + assert chain("a[[b[c]]]") == ["Part", "a", ["b", "c"]] + assert chain("a[[b[[c]]]]") == ["Part", "a", ["Part", "b", "c"]] + assert chain("a[[b[c[[d]]]]]") == ["Part", "a", ["b", ["Part", "c", "d"]]] + assert chain("a[b[[c[d]]]]") == ["a", ["Part", "b", ["c", "d"]]] + assert chain("x[[a+1, b+2, c+3]]") == ["Part", "x", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]] + assert chain("x[a+1, b+2, c+3]") == ["x", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]] + assert chain("{a+1, b+2, c+3}") == ["List", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]] + + # Flat operator: + assert chain("a*b*c*d*e") == ["Times", "a", "b", "c", "d", "e"] + assert chain("a +b + c+ d+e") == ["Plus", "a", "b", "c", "d", "e"] + + # Right priority operator: + assert chain("a^b") == ["Power", "a", "b"] + assert chain("a^b^c") == ["Power", "a", ["Power", "b", "c"]] + assert chain("a^b^c^d") == ["Power", "a", ["Power", "b", ["Power", "c", "d"]]] + + # Left priority operator: + assert chain("a/.b") == ["ReplaceAll", "a", "b"] + assert chain("a/.b/.c/.d") == ["ReplaceAll", ["ReplaceAll", ["ReplaceAll", "a", "b"], "c"], "d"] + + assert chain("a//b") == ["a", "b"] + assert chain("a//b//c") == [["a", "b"], "c"] + assert chain("a//b//c//d") == [[["a", "b"], "c"], "d"] + + # Compound expressions + assert chain("a;b") == ["CompoundExpression", "a", "b"] + assert chain("a;") == ["CompoundExpression", "a", "Null"] + assert chain("a;b;") == ["CompoundExpression", "a", "b", "Null"] + assert chain("a[b;c]") == ["a", ["CompoundExpression", "b", "c"]] + assert chain("a[b,c;d,e]") == ["a", "b", ["CompoundExpression", "c", "d"], "e"] + assert chain("a[b,c;,d]") == ["a", "b", ["CompoundExpression", "c", "Null"], "d"] + + # New lines + assert chain("a\nb\n") == ["CompoundExpression", "a", "b"] + assert chain("a\n\nb\n (c \nd) \n") == ["CompoundExpression", "a", "b", ["Times", "c", "d"]] + assert chain("\na; b\nc") == ["CompoundExpression", "a", "b", "c"] + assert chain("a + \nb\n") == ["Plus", "a", "b"] + assert chain("a\nb; c; d\n e; (f \n g); h + \n i") == ["CompoundExpression", "a", "b", "c", "d", "e", ["Times", "f", "g"], ["Plus", "h", "i"]] + assert chain("\n{\na\nb; c; d\n e (f \n g); h + \n i\n\n}\n") == ["List", ["CompoundExpression", ["Times", "a", "b"], "c", ["Times", "d", "e", ["Times", "f", "g"]], ["Plus", "h", "i"]]] + + # Patterns + assert chain("y_") == ["Pattern", "y", ["Blank"]] + assert chain("y_.") == ["Optional", ["Pattern", "y", ["Blank"]]] + assert chain("y__") == ["Pattern", "y", ["BlankSequence"]] + assert chain("y___") == ["Pattern", "y", ["BlankNullSequence"]] + assert chain("a[b_.,c_]") == ["a", ["Optional", ["Pattern", "b", ["Blank"]]], ["Pattern", "c", ["Blank"]]] + assert chain("b_. c") == ["Times", ["Optional", ["Pattern", "b", ["Blank"]]], "c"] + + # Slots for lambda functions + assert chain("#") == ["Slot", "1"] + assert chain("#3") == ["Slot", "3"] + assert chain("#n") == ["Slot", "n"] + assert chain("##") == ["SlotSequence", "1"] + assert chain("##a") == ["SlotSequence", "a"] + + # Lambda functions + assert chain("x&") == ["Function", "x"] + assert chain("#&") == ["Function", ["Slot", "1"]] + assert chain("#+3&") == ["Function", ["Plus", ["Slot", "1"], "3"]] + assert chain("#1 + #2&") == ["Function", ["Plus", ["Slot", "1"], ["Slot", "2"]]] + assert chain("# + #&") == ["Function", ["Plus", ["Slot", "1"], ["Slot", "1"]]] + assert chain("#&[x]") == [["Function", ["Slot", "1"]], "x"] + assert chain("#1 + #2 & [x, y]") == [["Function", ["Plus", ["Slot", "1"], ["Slot", "2"]]], "x", "y"] + assert chain("#1^2#2^3&") == ["Function", ["Times", ["Power", ["Slot", "1"], "2"], ["Power", ["Slot", "2"], "3"]]] + + # Strings inside Mathematica expressions: + assert chain('"abc"') == ["_Str", "abc"] + assert chain('"a\\"b"') == ["_Str", 'a"b'] + # This expression does not make sense mathematically, it's just testing the parser: + assert chain('x + "abc" ^ 3') == ["Plus", "x", ["Power", ["_Str", "abc"], "3"]] + assert chain('"a (* b *) c"') == ["_Str", "a (* b *) c"] + assert chain('"a" (* b *) ') == ["_Str", "a"] + assert chain('"a [ b] "') == ["_Str", "a [ b] "] + raises(SyntaxError, lambda: chain('"')) + raises(SyntaxError, lambda: chain('"\\"')) + raises(SyntaxError, lambda: chain('"abc')) + raises(SyntaxError, lambda: chain('"abc\\"def')) + + # Invalid expressions: + raises(SyntaxError, lambda: chain("(,")) + raises(SyntaxError, lambda: chain("()")) + raises(SyntaxError, lambda: chain("a (* b")) + + +def test_parser_mathematica_exp_alt(): + parser = MathematicaParser() + + convert_chain2 = lambda expr: parser._from_fullformlist_to_fullformsympy(parser._from_fullform_to_fullformlist(expr)) + convert_chain3 = lambda expr: parser._from_fullformsympy_to_sympy(convert_chain2(expr)) + + Sin, Times, Plus, Power = symbols("Sin Times Plus Power", cls=Function) + + full_form1 = "Sin[Times[x, y]]" + full_form2 = "Plus[Times[x, y], z]" + full_form3 = "Sin[Times[x, Plus[y, z], Power[w, n]]]]" + full_form4 = "Rational[Rational[x, y], z]" + + assert parser._from_fullform_to_fullformlist(full_form1) == ["Sin", ["Times", "x", "y"]] + assert parser._from_fullform_to_fullformlist(full_form2) == ["Plus", ["Times", "x", "y"], "z"] + assert parser._from_fullform_to_fullformlist(full_form3) == ["Sin", ["Times", "x", ["Plus", "y", "z"], ["Power", "w", "n"]]] + assert parser._from_fullform_to_fullformlist(full_form4) == ["Rational", ["Rational", "x", "y"], "z"] + + assert convert_chain2(full_form1) == Sin(Times(x, y)) + assert convert_chain2(full_form2) == Plus(Times(x, y), z) + assert convert_chain2(full_form3) == Sin(Times(x, Plus(y, z), Power(w, n))) + + assert convert_chain3(full_form1) == sin(x*y) + assert convert_chain3(full_form2) == x*y + z + assert convert_chain3(full_form3) == sin(x*(y + z)*w**n) diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_sym_expr.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_sym_expr.py new file mode 100644 index 0000000000000000000000000000000000000000..99912805db381b96e7f41a348fe6f90d71adf781 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_sym_expr.py @@ -0,0 +1,209 @@ +from sympy.parsing.sym_expr import SymPyExpression +from sympy.testing.pytest import raises +from sympy.external import import_module + +lfortran = import_module('lfortran') +cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) + +if lfortran and cin: + from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String, + Declaration, FloatType) + from sympy.core import Integer, Float + from sympy.core.symbol import Symbol + + expr1 = SymPyExpression() + src = """\ + integer :: a, b, c, d + real :: p, q, r, s + """ + + def test_c_parse(): + src1 = """\ + int a, b = 4; + float c, d = 2.4; + """ + expr1.convert_to_expr(src1, 'c') + ls = expr1.return_expr() + + assert ls[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('intc')) + ) + ) + assert ls[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('intc')), + value=Integer(4) + ) + ) + assert ls[2] == Declaration( + Variable( + Symbol('c'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ) + ) + ) + assert ls[3] == Declaration( + Variable( + Symbol('d'), + type=FloatType( + String('float32'), + nbits=Integer(32), + nmant=Integer(23), + nexp=Integer(8) + ), + value=Float('2.3999999999999999', precision=53) + ) + ) + + + def test_fortran_parse(): + expr = SymPyExpression(src, 'f') + ls = expr.return_expr() + + assert ls[0] == Declaration( + Variable( + Symbol('a'), + type=IntBaseType(String('integer')), + value=Integer(0) + ) + ) + assert ls[1] == Declaration( + Variable( + Symbol('b'), + type=IntBaseType(String('integer')), + value=Integer(0) + ) + ) + assert ls[2] == Declaration( + Variable( + Symbol('c'), + type=IntBaseType(String('integer')), + value=Integer(0) + ) + ) + assert ls[3] == Declaration( + Variable( + Symbol('d'), + type=IntBaseType(String('integer')), + value=Integer(0) + ) + ) + assert ls[4] == Declaration( + Variable( + Symbol('p'), + type=FloatBaseType(String('real')), + value=Float('0.0', precision=53) + ) + ) + assert ls[5] == Declaration( + Variable( + Symbol('q'), + type=FloatBaseType(String('real')), + value=Float('0.0', precision=53) + ) + ) + assert ls[6] == Declaration( + Variable( + Symbol('r'), + type=FloatBaseType(String('real')), + value=Float('0.0', precision=53) + ) + ) + assert ls[7] == Declaration( + Variable( + Symbol('s'), + type=FloatBaseType(String('real')), + value=Float('0.0', precision=53) + ) + ) + + + def test_convert_py(): + src1 = ( + src + + """\ + a = b + c + s = p * q / r + """ + ) + expr1.convert_to_expr(src1, 'f') + exp_py = expr1.convert_to_python() + assert exp_py == [ + 'a = 0', + 'b = 0', + 'c = 0', + 'd = 0', + 'p = 0.0', + 'q = 0.0', + 'r = 0.0', + 's = 0.0', + 'a = b + c', + 's = p*q/r' + ] + + + def test_convert_fort(): + src1 = ( + src + + """\ + a = b + c + s = p * q / r + """ + ) + expr1.convert_to_expr(src1, 'f') + exp_fort = expr1.convert_to_fortran() + assert exp_fort == [ + ' integer*4 a', + ' integer*4 b', + ' integer*4 c', + ' integer*4 d', + ' real*8 p', + ' real*8 q', + ' real*8 r', + ' real*8 s', + ' a = b + c', + ' s = p*q/r' + ] + + + def test_convert_c(): + src1 = ( + src + + """\ + a = b + c + s = p * q / r + """ + ) + expr1.convert_to_expr(src1, 'f') + exp_c = expr1.convert_to_c() + assert exp_c == [ + 'int a = 0', + 'int b = 0', + 'int c = 0', + 'int d = 0', + 'double p = 0.0', + 'double q = 0.0', + 'double r = 0.0', + 'double s = 0.0', + 'a = b + c;', + 's = p*q/r;' + ] + + + def test_exceptions(): + src = 'int a;' + raises(ValueError, lambda: SymPyExpression(src)) + raises(ValueError, lambda: SymPyExpression(mode = 'c')) + raises(NotImplementedError, lambda: SymPyExpression(src, mode = 'd')) + +elif not lfortran and not cin: + def test_raise(): + raises(ImportError, lambda: SymPyExpression('int a;', 'c')) + raises(ImportError, lambda: SymPyExpression('integer :: a', 'f')) diff --git a/lib/python3.12/site-packages/sympy/parsing/tests/test_sympy_parser.py b/lib/python3.12/site-packages/sympy/parsing/tests/test_sympy_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..6088ceffd9078bfaabc571584df0608bb1416020 --- /dev/null +++ b/lib/python3.12/site-packages/sympy/parsing/tests/test_sympy_parser.py @@ -0,0 +1,372 @@ +# -*- coding: utf-8 -*- + + +import sys +import builtins +import types + +from sympy.assumptions import Q +from sympy.core import Symbol, Function, Float, Rational, Integer, I, Mul, Pow, Eq, Lt, Le, Gt, Ge, Ne +from sympy.functions import exp, factorial, factorial2, sin, Min, Max +from sympy.logic import And +from sympy.series import Limit +from sympy.testing.pytest import raises, skip + +from sympy.parsing.sympy_parser import ( + parse_expr, standard_transformations, rationalize, TokenError, + split_symbols, implicit_multiplication, convert_equals_signs, + convert_xor, function_exponentiation, lambda_notation, auto_symbol, + repeated_decimals, implicit_multiplication_application, + auto_number, factorial_notation, implicit_application, + _transformation, T + ) + + +def test_sympy_parser(): + x = Symbol('x') + inputs = { + '2*x': 2 * x, + '3.00': Float(3), + '22/7': Rational(22, 7), + '2+3j': 2 + 3*I, + 'exp(x)': exp(x), + 'x!': factorial(x), + 'x!!': factorial2(x), + '(x + 1)! - 1': factorial(x + 1) - 1, + '3.[3]': Rational(10, 3), + '.0[3]': Rational(1, 30), + '3.2[3]': Rational(97, 30), + '1.3[12]': Rational(433, 330), + '1 + 3.[3]': Rational(13, 3), + '1 + .0[3]': Rational(31, 30), + '1 + 3.2[3]': Rational(127, 30), + '.[0011]': Rational(1, 909), + '0.1[00102] + 1': Rational(366697, 333330), + '1.[0191]': Rational(10190, 9999), + '10!': 3628800, + '-(2)': -Integer(2), + '[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)], + 'Symbol("x").free_symbols': x.free_symbols, + "S('S(3).n(n=3)')": Float(3, 3), + 'factorint(12, visual=True)': Mul( + Pow(2, 2, evaluate=False), + Pow(3, 1, evaluate=False), + evaluate=False), + 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'), + 'Q.even(x)': Q.even(x), + + + } + for text, result in inputs.items(): + assert parse_expr(text) == result + + raises(TypeError, lambda: + parse_expr('x', standard_transformations)) + raises(TypeError, lambda: + parse_expr('x', transformations=lambda x,y: 1)) + raises(TypeError, lambda: + parse_expr('x', transformations=(lambda x,y: 1,))) + raises(TypeError, lambda: parse_expr('x', transformations=((),))) + raises(TypeError, lambda: parse_expr('x', {}, [], [])) + raises(TypeError, lambda: parse_expr('x', [], [], {})) + raises(TypeError, lambda: parse_expr('x', [], [], {})) + + +def test_rationalize(): + inputs = { + '0.123': Rational(123, 1000) + } + transformations = standard_transformations + (rationalize,) + for text, result in inputs.items(): + assert parse_expr(text, transformations=transformations) == result + + +def test_factorial_fail(): + inputs = ['x!!!', 'x!!!!', '(!)'] + + + for text in inputs: + try: + parse_expr(text) + assert False + except TokenError: + assert True + + +def test_repeated_fail(): + inputs = ['1[1]', '.1e1[1]', '0x1[1]', '1.1j[1]', '1.1[1 + 1]', + '0.1[[1]]', '0x1.1[1]'] + + + # All are valid Python, so only raise TypeError for invalid indexing + for text in inputs: + raises(TypeError, lambda: parse_expr(text)) + + + inputs = ['0.1[', '0.1[1', '0.1[]'] + for text in inputs: + raises((TokenError, SyntaxError), lambda: parse_expr(text)) + + +def test_repeated_dot_only(): + assert parse_expr('.[1]') == Rational(1, 9) + assert parse_expr('1 + .[1]') == Rational(10, 9) + + +def test_local_dict(): + local_dict = { + 'my_function': lambda x: x + 2 + } + inputs = { + 'my_function(2)': Integer(4) + } + for text, result in inputs.items(): + assert parse_expr(text, local_dict=local_dict) == result + + +def test_local_dict_split_implmult(): + t = standard_transformations + (split_symbols, implicit_multiplication,) + w = Symbol('w', real=True) + y = Symbol('y') + assert parse_expr('yx', local_dict={'x':w}, transformations=t) == y*w + + +def test_local_dict_symbol_to_fcn(): + x = Symbol('x') + d = {'foo': Function('bar')} + assert parse_expr('foo(x)', local_dict=d) == d['foo'](x) + d = {'foo': Symbol('baz')} + raises(TypeError, lambda: parse_expr('foo(x)', local_dict=d)) + + +def test_global_dict(): + global_dict = { + 'Symbol': Symbol + } + inputs = { + 'Q & S': And(Symbol('Q'), Symbol('S')) + } + for text, result in inputs.items(): + assert parse_expr(text, global_dict=global_dict) == result + + +def test_no_globals(): + + # Replicate creating the default global_dict: + default_globals = {} + exec('from sympy import *', default_globals) + builtins_dict = vars(builtins) + for name, obj in builtins_dict.items(): + if isinstance(obj, types.BuiltinFunctionType): + default_globals[name] = obj + default_globals['max'] = Max + default_globals['min'] = Min + + # Need to include Symbol or parse_expr will not work: + default_globals.pop('Symbol') + global_dict = {'Symbol':Symbol} + + for name in default_globals: + obj = parse_expr(name, global_dict=global_dict) + assert obj == Symbol(name) + + +def test_issue_2515(): + raises(TokenError, lambda: parse_expr('(()')) + raises(TokenError, lambda: parse_expr('"""')) + + +def test_issue_7663(): + x = Symbol('x') + e = '2*(x+1)' + assert parse_expr(e, evaluate=0) == parse_expr(e, evaluate=False) + assert parse_expr(e, evaluate=0).equals(2*(x+1)) + +def test_recursive_evaluate_false_10560(): + inputs = { + '4*-3' : '4*-3', + '-4*3' : '(-4)*3', + "-2*x*y": '(-2)*x*y', + "x*-4*x": "x*(-4)*x" + } + for text, result in inputs.items(): + assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False) + + +def test_function_evaluate_false(): + inputs = [ + 'Abs(0)', 'im(0)', 're(0)', 'sign(0)', 'arg(0)', 'conjugate(0)', + 'acos(0)', 'acot(0)', 'acsc(0)', 'asec(0)', 'asin(0)', 'atan(0)', + 'acosh(0)', 'acoth(0)', 'acsch(0)', 'asech(0)', 'asinh(0)', 'atanh(0)', + 'cos(0)', 'cot(0)', 'csc(0)', 'sec(0)', 'sin(0)', 'tan(0)', + 'cosh(0)', 'coth(0)', 'csch(0)', 'sech(0)', 'sinh(0)', 'tanh(0)', + 'exp(0)', 'log(0)', 'sqrt(0)', + ] + for case in inputs: + expr = parse_expr(case, evaluate=False) + assert case == str(expr) != str(expr.doit()) + assert str(parse_expr('ln(0)', evaluate=False)) == 'log(0)' + assert str(parse_expr('cbrt(0)', evaluate=False)) == '0**(1/3)' + + +def test_issue_10773(): + inputs = { + '-10/5': '(-10)/5', + '-10/-5' : '(-10)/(-5)', + } + for text, result in inputs.items(): + assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False) + + +def test_split_symbols(): + transformations = standard_transformations + \ + (split_symbols, implicit_multiplication,) + x = Symbol('x') + y = Symbol('y') + xy = Symbol('xy') + + + assert parse_expr("xy") == xy + assert parse_expr("xy", transformations=transformations) == x*y + + +def test_split_symbols_function(): + transformations = standard_transformations + \ + (split_symbols, implicit_multiplication,) + x = Symbol('x') + y = Symbol('y') + a = Symbol('a') + f = Function('f') + + + assert parse_expr("ay(x+1)", transformations=transformations) == a*y*(x+1) + assert parse_expr("af(x+1)", transformations=transformations, + local_dict={'f':f}) == a*f(x+1) + + +def test_functional_exponent(): + t = standard_transformations + (convert_xor, function_exponentiation) + x = Symbol('x') + y = Symbol('y') + a = Symbol('a') + yfcn = Function('y') + assert parse_expr("sin^2(x)", transformations=t) == (sin(x))**2 + assert parse_expr("sin^y(x)", transformations=t) == (sin(x))**y + assert parse_expr("exp^y(x)", transformations=t) == (exp(x))**y + assert parse_expr("E^y(x)", transformations=t) == exp(yfcn(x)) + assert parse_expr("a^y(x)", transformations=t) == a**(yfcn(x)) + + +def test_match_parentheses_implicit_multiplication(): + transformations = standard_transformations + \ + (implicit_multiplication,) + raises(TokenError, lambda: parse_expr('(1,2),(3,4]',transformations=transformations)) + + +def test_convert_equals_signs(): + transformations = standard_transformations + \ + (convert_equals_signs, ) + x = Symbol('x') + y = Symbol('y') + assert parse_expr("1*2=x", transformations=transformations) == Eq(2, x) + assert parse_expr("y = x", transformations=transformations) == Eq(y, x) + assert parse_expr("(2*y = x) = False", + transformations=transformations) == Eq(Eq(2*y, x), False) + + +def test_parse_function_issue_3539(): + x = Symbol('x') + f = Function('f') + assert parse_expr('f(x)') == f(x) + +def test_issue_24288(): + inputs = { + "1 < 2": Lt(1, 2, evaluate=False), + "1 <= 2": Le(1, 2, evaluate=False), + "1 > 2": Gt(1, 2, evaluate=False), + "1 >= 2": Ge(1, 2, evaluate=False), + "1 != 2": Ne(1, 2, evaluate=False), + "1 == 2": Eq(1, 2, evaluate=False) + } + for text, result in inputs.items(): + assert parse_expr(text, evaluate=False) == result + +def test_split_symbols_numeric(): + transformations = ( + standard_transformations + + (implicit_multiplication_application,)) + + n = Symbol('n') + expr1 = parse_expr('2**n * 3**n') + expr2 = parse_expr('2**n3**n', transformations=transformations) + assert expr1 == expr2 == 2**n*3**n + + expr1 = parse_expr('n12n34', transformations=transformations) + assert expr1 == n*12*n*34 + + +def test_unicode_names(): + assert parse_expr('α') == Symbol('α') + + +def test_python3_features(): + # Make sure the tokenizer can handle Python 3-only features + if sys.version_info < (3, 8): + skip("test_python3_features requires Python 3.8 or newer") + + + assert parse_expr("123_456") == 123456 + assert parse_expr("1.2[3_4]") == parse_expr("1.2[34]") == Rational(611, 495) + assert parse_expr("1.2[012_012]") == parse_expr("1.2[012012]") == Rational(400, 333) + assert parse_expr('.[3_4]') == parse_expr('.[34]') == Rational(34, 99) + assert parse_expr('.1[3_4]') == parse_expr('.1[34]') == Rational(133, 990) + assert parse_expr('123_123.123_123[3_4]') == parse_expr('123123.123123[34]') == Rational(12189189189211, 99000000) + + +def test_issue_19501(): + x = Symbol('x') + eq = parse_expr('E**x(1+x)', local_dict={'x': x}, transformations=( + standard_transformations + + (implicit_multiplication_application,))) + assert eq.free_symbols == {x} + + +def test_parsing_definitions(): + from sympy.abc import x + assert len(_transformation) == 12 # if this changes, extend below + assert _transformation[0] == lambda_notation + assert _transformation[1] == auto_symbol + assert _transformation[2] == repeated_decimals + assert _transformation[3] == auto_number + assert _transformation[4] == factorial_notation + assert _transformation[5] == implicit_multiplication_application + assert _transformation[6] == convert_xor + assert _transformation[7] == implicit_application + assert _transformation[8] == implicit_multiplication + assert _transformation[9] == convert_equals_signs + assert _transformation[10] == function_exponentiation + assert _transformation[11] == rationalize + assert T[:5] == T[0,1,2,3,4] == standard_transformations + t = _transformation + assert T[-1, 0] == (t[len(t) - 1], t[0]) + assert T[:5, 8] == standard_transformations + (t[8],) + assert parse_expr('0.3x^2', transformations='all') == 3*x**2/10 + assert parse_expr('sin 3x', transformations='implicit') == sin(3*x) + + +def test_builtins(): + cases = [ + ('abs(x)', 'Abs(x)'), + ('max(x, y)', 'Max(x, y)'), + ('min(x, y)', 'Min(x, y)'), + ('pow(x, y)', 'Pow(x, y)'), + ] + for built_in_func_call, sympy_func_call in cases: + assert parse_expr(built_in_func_call) == parse_expr(sympy_func_call) + assert str(parse_expr('pow(38, -1, 97)')) == '23' + + +def test_issue_22822(): + raises(ValueError, lambda: parse_expr('x', {'': 1})) + data = {'some_parameter': None} + assert parse_expr('some_parameter is None', data) is True