Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/sympy/core/__init__.py +103 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/_print_helpers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/add.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/alphabets.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/assumptions.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/assumptions_generated.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/backend.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/basic.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/cache.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/compatibility.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/containers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/core.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/coreerrors.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/decorators.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/evalf.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/exprtools.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/facts.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/intfunc.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/kind.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/logic.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/mod.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/mul.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/multidimensional.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/operations.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/parameters.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/power.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/random.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/relational.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/rules.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/singleton.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/sorting.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/symbol.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/sympify.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/trace.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/__pycache__/traversal.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/core/_print_helpers.py +65 -0
- lib/python3.12/site-packages/sympy/core/add.py +1284 -0
- lib/python3.12/site-packages/sympy/core/alphabets.py +4 -0
- lib/python3.12/site-packages/sympy/core/assumptions.py +692 -0
- lib/python3.12/site-packages/sympy/core/assumptions_generated.py +1615 -0
- lib/python3.12/site-packages/sympy/core/backend.py +120 -0
- lib/python3.12/site-packages/sympy/core/basic.py +2339 -0
- lib/python3.12/site-packages/sympy/core/cache.py +210 -0
- lib/python3.12/site-packages/sympy/core/compatibility.py +35 -0
- lib/python3.12/site-packages/sympy/core/containers.py +410 -0
- lib/python3.12/site-packages/sympy/core/core.py +21 -0
- lib/python3.12/site-packages/sympy/core/coreerrors.py +9 -0
- lib/python3.12/site-packages/sympy/core/decorators.py +238 -0
- lib/python3.12/site-packages/sympy/core/evalf.py +1802 -0
lib/python3.12/site-packages/sympy/core/__init__.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Core module. Provides the basic operations needed in sympy.
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
from .sympify import sympify, SympifyError
|
| 5 |
+
from .cache import cacheit
|
| 6 |
+
from .assumptions import assumptions, check_assumptions, failing_assumptions, common_assumptions
|
| 7 |
+
from .basic import Basic, Atom
|
| 8 |
+
from .singleton import S
|
| 9 |
+
from .expr import Expr, AtomicExpr, UnevaluatedExpr
|
| 10 |
+
from .symbol import Symbol, Wild, Dummy, symbols, var
|
| 11 |
+
from .numbers import Number, Float, Rational, Integer, NumberSymbol, \
|
| 12 |
+
RealNumber, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo, \
|
| 13 |
+
AlgebraicNumber, comp, mod_inverse
|
| 14 |
+
from .power import Pow
|
| 15 |
+
from .intfunc import integer_nthroot, integer_log, num_digits, trailing
|
| 16 |
+
from .mul import Mul, prod
|
| 17 |
+
from .add import Add
|
| 18 |
+
from .mod import Mod
|
| 19 |
+
from .relational import ( Rel, Eq, Ne, Lt, Le, Gt, Ge,
|
| 20 |
+
Equality, GreaterThan, LessThan, Unequality, StrictGreaterThan,
|
| 21 |
+
StrictLessThan )
|
| 22 |
+
from .multidimensional import vectorize
|
| 23 |
+
from .function import Lambda, WildFunction, Derivative, diff, FunctionClass, \
|
| 24 |
+
Function, Subs, expand, PoleError, count_ops, \
|
| 25 |
+
expand_mul, expand_log, expand_func, \
|
| 26 |
+
expand_trig, expand_complex, expand_multinomial, nfloat, \
|
| 27 |
+
expand_power_base, expand_power_exp, arity
|
| 28 |
+
from .evalf import PrecisionExhausted, N
|
| 29 |
+
from .containers import Tuple, Dict
|
| 30 |
+
from .exprtools import gcd_terms, factor_terms, factor_nc
|
| 31 |
+
from .parameters import evaluate
|
| 32 |
+
from .kind import UndefinedKind, NumberKind, BooleanKind
|
| 33 |
+
from .traversal import preorder_traversal, bottom_up, use, postorder_traversal
|
| 34 |
+
from .sorting import default_sort_key, ordered
|
| 35 |
+
|
| 36 |
+
# expose singletons
|
| 37 |
+
Catalan = S.Catalan
|
| 38 |
+
EulerGamma = S.EulerGamma
|
| 39 |
+
GoldenRatio = S.GoldenRatio
|
| 40 |
+
TribonacciConstant = S.TribonacciConstant
|
| 41 |
+
|
| 42 |
+
__all__ = [
|
| 43 |
+
'sympify', 'SympifyError',
|
| 44 |
+
|
| 45 |
+
'cacheit',
|
| 46 |
+
|
| 47 |
+
'assumptions', 'check_assumptions', 'failing_assumptions',
|
| 48 |
+
'common_assumptions',
|
| 49 |
+
|
| 50 |
+
'Basic', 'Atom',
|
| 51 |
+
|
| 52 |
+
'S',
|
| 53 |
+
|
| 54 |
+
'Expr', 'AtomicExpr', 'UnevaluatedExpr',
|
| 55 |
+
|
| 56 |
+
'Symbol', 'Wild', 'Dummy', 'symbols', 'var',
|
| 57 |
+
|
| 58 |
+
'Number', 'Float', 'Rational', 'Integer', 'NumberSymbol', 'RealNumber',
|
| 59 |
+
'igcd', 'ilcm', 'seterr', 'E', 'I', 'nan', 'oo', 'pi', 'zoo',
|
| 60 |
+
'AlgebraicNumber', 'comp', 'mod_inverse',
|
| 61 |
+
|
| 62 |
+
'Pow',
|
| 63 |
+
|
| 64 |
+
'integer_nthroot', 'integer_log', 'num_digits', 'trailing',
|
| 65 |
+
|
| 66 |
+
'Mul', 'prod',
|
| 67 |
+
|
| 68 |
+
'Add',
|
| 69 |
+
|
| 70 |
+
'Mod',
|
| 71 |
+
|
| 72 |
+
'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 'Equality', 'GreaterThan',
|
| 73 |
+
'LessThan', 'Unequality', 'StrictGreaterThan', 'StrictLessThan',
|
| 74 |
+
|
| 75 |
+
'vectorize',
|
| 76 |
+
|
| 77 |
+
'Lambda', 'WildFunction', 'Derivative', 'diff', 'FunctionClass',
|
| 78 |
+
'Function', 'Subs', 'expand', 'PoleError', 'count_ops', 'expand_mul',
|
| 79 |
+
'expand_log', 'expand_func', 'expand_trig', 'expand_complex',
|
| 80 |
+
'expand_multinomial', 'nfloat', 'expand_power_base', 'expand_power_exp',
|
| 81 |
+
'arity',
|
| 82 |
+
|
| 83 |
+
'PrecisionExhausted', 'N',
|
| 84 |
+
|
| 85 |
+
'evalf', # The module?
|
| 86 |
+
|
| 87 |
+
'Tuple', 'Dict',
|
| 88 |
+
|
| 89 |
+
'gcd_terms', 'factor_terms', 'factor_nc',
|
| 90 |
+
|
| 91 |
+
'evaluate',
|
| 92 |
+
|
| 93 |
+
'Catalan',
|
| 94 |
+
'EulerGamma',
|
| 95 |
+
'GoldenRatio',
|
| 96 |
+
'TribonacciConstant',
|
| 97 |
+
|
| 98 |
+
'UndefinedKind', 'NumberKind', 'BooleanKind',
|
| 99 |
+
|
| 100 |
+
'preorder_traversal', 'bottom_up', 'use', 'postorder_traversal',
|
| 101 |
+
|
| 102 |
+
'default_sort_key', 'ordered',
|
| 103 |
+
]
|
lib/python3.12/site-packages/sympy/core/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (3.41 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/_print_helpers.cpython-312.pyc
ADDED
|
Binary file (2.45 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/add.cpython-312.pyc
ADDED
|
Binary file (54.6 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/alphabets.cpython-312.pyc
ADDED
|
Binary file (356 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/assumptions.cpython-312.pyc
ADDED
|
Binary file (21.8 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/assumptions_generated.cpython-312.pyc
ADDED
|
Binary file (15.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/backend.cpython-312.pyc
ADDED
|
Binary file (4.58 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/basic.cpython-312.pyc
ADDED
|
Binary file (84.2 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/cache.cpython-312.pyc
ADDED
|
Binary file (8.46 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/compatibility.cpython-312.pyc
ADDED
|
Binary file (1.35 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/containers.cpython-312.pyc
ADDED
|
Binary file (19 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/core.cpython-312.pyc
ADDED
|
Binary file (1.19 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/coreerrors.cpython-312.pyc
ADDED
|
Binary file (738 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/decorators.cpython-312.pyc
ADDED
|
Binary file (9.41 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/evalf.cpython-312.pyc
ADDED
|
Binary file (65 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/exprtools.cpython-312.pyc
ADDED
|
Binary file (62.3 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/facts.cpython-312.pyc
ADDED
|
Binary file (23.6 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/intfunc.cpython-312.pyc
ADDED
|
Binary file (14.4 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/kind.cpython-312.pyc
ADDED
|
Binary file (14.7 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/logic.cpython-312.pyc
ADDED
|
Binary file (14 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/mod.cpython-312.pyc
ADDED
|
Binary file (11.2 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/mul.cpython-312.pyc
ADDED
|
Binary file (86.6 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/multidimensional.cpython-312.pyc
ADDED
|
Binary file (4.92 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/operations.cpython-312.pyc
ADDED
|
Binary file (28.3 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/parameters.cpython-312.pyc
ADDED
|
Binary file (5.48 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/power.cpython-312.pyc
ADDED
|
Binary file (88.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/random.cpython-312.pyc
ADDED
|
Binary file (8.85 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/relational.cpython-312.pyc
ADDED
|
Binary file (59.9 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/rules.cpython-312.pyc
ADDED
|
Binary file (2.32 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/singleton.cpython-312.pyc
ADDED
|
Binary file (7.48 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/sorting.cpython-312.pyc
ADDED
|
Binary file (12.3 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/symbol.cpython-312.pyc
ADDED
|
Binary file (35.8 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/sympify.cpython-312.pyc
ADDED
|
Binary file (20 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/trace.cpython-312.pyc
ADDED
|
Binary file (544 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/core/__pycache__/traversal.cpython-312.pyc
ADDED
|
Binary file (10.8 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/core/_print_helpers.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Base class to provide str and repr hooks that `init_printing` can overwrite.
|
| 3 |
+
|
| 4 |
+
This is exposed publicly in the `printing.defaults` module,
|
| 5 |
+
but cannot be defined there without causing circular imports.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
class Printable:
|
| 9 |
+
"""
|
| 10 |
+
The default implementation of printing for SymPy classes.
|
| 11 |
+
|
| 12 |
+
This implements a hack that allows us to print elements of built-in
|
| 13 |
+
Python containers in a readable way. Natively Python uses ``repr()``
|
| 14 |
+
even if ``str()`` was explicitly requested. Mix in this trait into
|
| 15 |
+
a class to get proper default printing.
|
| 16 |
+
|
| 17 |
+
This also adds support for LaTeX printing in jupyter notebooks.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
# Since this class is used as a mixin we set empty slots. That means that
|
| 21 |
+
# instances of any subclasses that use slots will not need to have a
|
| 22 |
+
# __dict__.
|
| 23 |
+
__slots__ = ()
|
| 24 |
+
|
| 25 |
+
# Note, we always use the default ordering (lex) in __str__ and __repr__,
|
| 26 |
+
# regardless of the global setting. See issue 5487.
|
| 27 |
+
def __str__(self):
|
| 28 |
+
from sympy.printing.str import sstr
|
| 29 |
+
return sstr(self, order=None)
|
| 30 |
+
|
| 31 |
+
__repr__ = __str__
|
| 32 |
+
|
| 33 |
+
def _repr_disabled(self):
|
| 34 |
+
"""
|
| 35 |
+
No-op repr function used to disable jupyter display hooks.
|
| 36 |
+
|
| 37 |
+
When :func:`sympy.init_printing` is used to disable certain display
|
| 38 |
+
formats, this function is copied into the appropriate ``_repr_*_``
|
| 39 |
+
attributes.
|
| 40 |
+
|
| 41 |
+
While we could just set the attributes to `None``, doing it this way
|
| 42 |
+
allows derived classes to call `super()`.
|
| 43 |
+
"""
|
| 44 |
+
return None
|
| 45 |
+
|
| 46 |
+
# We don't implement _repr_png_ here because it would add a large amount of
|
| 47 |
+
# data to any notebook containing SymPy expressions, without adding
|
| 48 |
+
# anything useful to the notebook. It can still enabled manually, e.g.,
|
| 49 |
+
# for the qtconsole, with init_printing().
|
| 50 |
+
_repr_png_ = _repr_disabled
|
| 51 |
+
|
| 52 |
+
_repr_svg_ = _repr_disabled
|
| 53 |
+
|
| 54 |
+
def _repr_latex_(self):
|
| 55 |
+
"""
|
| 56 |
+
IPython/Jupyter LaTeX printing
|
| 57 |
+
|
| 58 |
+
To change the behavior of this (e.g., pass in some settings to LaTeX),
|
| 59 |
+
use init_printing(). init_printing() will also enable LaTeX printing
|
| 60 |
+
for built in numeric types like ints and container types that contain
|
| 61 |
+
SymPy objects, like lists and dictionaries of expressions.
|
| 62 |
+
"""
|
| 63 |
+
from sympy.printing.latex import latex
|
| 64 |
+
s = latex(self, mode='plain')
|
| 65 |
+
return "$\\displaystyle %s$" % s
|
lib/python3.12/site-packages/sympy/core/add.py
ADDED
|
@@ -0,0 +1,1284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Tuple as tTuple
|
| 2 |
+
from collections import defaultdict
|
| 3 |
+
from functools import reduce
|
| 4 |
+
from operator import attrgetter
|
| 5 |
+
from .basic import _args_sortkey
|
| 6 |
+
from .parameters import global_parameters
|
| 7 |
+
from .logic import _fuzzy_group, fuzzy_or, fuzzy_not
|
| 8 |
+
from .singleton import S
|
| 9 |
+
from .operations import AssocOp, AssocOpDispatcher
|
| 10 |
+
from .cache import cacheit
|
| 11 |
+
from .numbers import equal_valued
|
| 12 |
+
from .intfunc import ilcm, igcd
|
| 13 |
+
from .expr import Expr
|
| 14 |
+
from .kind import UndefinedKind
|
| 15 |
+
from sympy.utilities.iterables import is_sequence, sift
|
| 16 |
+
|
| 17 |
+
def _could_extract_minus_sign(expr):
|
| 18 |
+
# assume expr is Add-like
|
| 19 |
+
# We choose the one with less arguments with minus signs
|
| 20 |
+
negative_args = sum(1 for i in expr.args
|
| 21 |
+
if i.could_extract_minus_sign())
|
| 22 |
+
positive_args = len(expr.args) - negative_args
|
| 23 |
+
if positive_args > negative_args:
|
| 24 |
+
return False
|
| 25 |
+
elif positive_args < negative_args:
|
| 26 |
+
return True
|
| 27 |
+
# choose based on .sort_key() to prefer
|
| 28 |
+
# x - 1 instead of 1 - x and
|
| 29 |
+
# 3 - sqrt(2) instead of -3 + sqrt(2)
|
| 30 |
+
return bool(expr.sort_key() < (-expr).sort_key())
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _addsort(args):
|
| 34 |
+
# in-place sorting of args
|
| 35 |
+
args.sort(key=_args_sortkey)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _unevaluated_Add(*args):
|
| 39 |
+
"""Return a well-formed unevaluated Add: Numbers are collected and
|
| 40 |
+
put in slot 0 and args are sorted. Use this when args have changed
|
| 41 |
+
but you still want to return an unevaluated Add.
|
| 42 |
+
|
| 43 |
+
Examples
|
| 44 |
+
========
|
| 45 |
+
|
| 46 |
+
>>> from sympy.core.add import _unevaluated_Add as uAdd
|
| 47 |
+
>>> from sympy import S, Add
|
| 48 |
+
>>> from sympy.abc import x, y
|
| 49 |
+
>>> a = uAdd(*[S(1.0), x, S(2)])
|
| 50 |
+
>>> a.args[0]
|
| 51 |
+
3.00000000000000
|
| 52 |
+
>>> a.args[1]
|
| 53 |
+
x
|
| 54 |
+
|
| 55 |
+
Beyond the Number being in slot 0, there is no other assurance of
|
| 56 |
+
order for the arguments since they are hash sorted. So, for testing
|
| 57 |
+
purposes, output produced by this in some other function can only
|
| 58 |
+
be tested against the output of this function or as one of several
|
| 59 |
+
options:
|
| 60 |
+
|
| 61 |
+
>>> opts = (Add(x, y, evaluate=False), Add(y, x, evaluate=False))
|
| 62 |
+
>>> a = uAdd(x, y)
|
| 63 |
+
>>> assert a in opts and a == uAdd(x, y)
|
| 64 |
+
>>> uAdd(x + 1, x + 2)
|
| 65 |
+
x + x + 3
|
| 66 |
+
"""
|
| 67 |
+
args = list(args)
|
| 68 |
+
newargs = []
|
| 69 |
+
co = S.Zero
|
| 70 |
+
while args:
|
| 71 |
+
a = args.pop()
|
| 72 |
+
if a.is_Add:
|
| 73 |
+
# this will keep nesting from building up
|
| 74 |
+
# so that x + (x + 1) -> x + x + 1 (3 args)
|
| 75 |
+
args.extend(a.args)
|
| 76 |
+
elif a.is_Number:
|
| 77 |
+
co += a
|
| 78 |
+
else:
|
| 79 |
+
newargs.append(a)
|
| 80 |
+
_addsort(newargs)
|
| 81 |
+
if co:
|
| 82 |
+
newargs.insert(0, co)
|
| 83 |
+
return Add._from_args(newargs)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class Add(Expr, AssocOp):
|
| 87 |
+
"""
|
| 88 |
+
Expression representing addition operation for algebraic group.
|
| 89 |
+
|
| 90 |
+
.. deprecated:: 1.7
|
| 91 |
+
|
| 92 |
+
Using arguments that aren't subclasses of :class:`~.Expr` in core
|
| 93 |
+
operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is
|
| 94 |
+
deprecated. See :ref:`non-expr-args-deprecated` for details.
|
| 95 |
+
|
| 96 |
+
Every argument of ``Add()`` must be ``Expr``. Infix operator ``+``
|
| 97 |
+
on most scalar objects in SymPy calls this class.
|
| 98 |
+
|
| 99 |
+
Another use of ``Add()`` is to represent the structure of abstract
|
| 100 |
+
addition so that its arguments can be substituted to return different
|
| 101 |
+
class. Refer to examples section for this.
|
| 102 |
+
|
| 103 |
+
``Add()`` evaluates the argument unless ``evaluate=False`` is passed.
|
| 104 |
+
The evaluation logic includes:
|
| 105 |
+
|
| 106 |
+
1. Flattening
|
| 107 |
+
``Add(x, Add(y, z))`` -> ``Add(x, y, z)``
|
| 108 |
+
|
| 109 |
+
2. Identity removing
|
| 110 |
+
``Add(x, 0, y)`` -> ``Add(x, y)``
|
| 111 |
+
|
| 112 |
+
3. Coefficient collecting by ``.as_coeff_Mul()``
|
| 113 |
+
``Add(x, 2*x)`` -> ``Mul(3, x)``
|
| 114 |
+
|
| 115 |
+
4. Term sorting
|
| 116 |
+
``Add(y, x, 2)`` -> ``Add(2, x, y)``
|
| 117 |
+
|
| 118 |
+
If no argument is passed, identity element 0 is returned. If single
|
| 119 |
+
element is passed, that element is returned.
|
| 120 |
+
|
| 121 |
+
Note that ``Add(*args)`` is more efficient than ``sum(args)`` because
|
| 122 |
+
it flattens the arguments. ``sum(a, b, c, ...)`` recursively adds the
|
| 123 |
+
arguments as ``a + (b + (c + ...))``, which has quadratic complexity.
|
| 124 |
+
On the other hand, ``Add(a, b, c, d)`` does not assume nested
|
| 125 |
+
structure, making the complexity linear.
|
| 126 |
+
|
| 127 |
+
Since addition is group operation, every argument should have the
|
| 128 |
+
same :obj:`sympy.core.kind.Kind()`.
|
| 129 |
+
|
| 130 |
+
Examples
|
| 131 |
+
========
|
| 132 |
+
|
| 133 |
+
>>> from sympy import Add, I
|
| 134 |
+
>>> from sympy.abc import x, y
|
| 135 |
+
>>> Add(x, 1)
|
| 136 |
+
x + 1
|
| 137 |
+
>>> Add(x, x)
|
| 138 |
+
2*x
|
| 139 |
+
>>> 2*x**2 + 3*x + I*y + 2*y + 2*x/5 + 1.0*y + 1
|
| 140 |
+
2*x**2 + 17*x/5 + 3.0*y + I*y + 1
|
| 141 |
+
|
| 142 |
+
If ``evaluate=False`` is passed, result is not evaluated.
|
| 143 |
+
|
| 144 |
+
>>> Add(1, 2, evaluate=False)
|
| 145 |
+
1 + 2
|
| 146 |
+
>>> Add(x, x, evaluate=False)
|
| 147 |
+
x + x
|
| 148 |
+
|
| 149 |
+
``Add()`` also represents the general structure of addition operation.
|
| 150 |
+
|
| 151 |
+
>>> from sympy import MatrixSymbol
|
| 152 |
+
>>> A,B = MatrixSymbol('A', 2,2), MatrixSymbol('B', 2,2)
|
| 153 |
+
>>> expr = Add(x,y).subs({x:A, y:B})
|
| 154 |
+
>>> expr
|
| 155 |
+
A + B
|
| 156 |
+
>>> type(expr)
|
| 157 |
+
<class 'sympy.matrices.expressions.matadd.MatAdd'>
|
| 158 |
+
|
| 159 |
+
Note that the printers do not display in args order.
|
| 160 |
+
|
| 161 |
+
>>> Add(x, 1)
|
| 162 |
+
x + 1
|
| 163 |
+
>>> Add(x, 1).args
|
| 164 |
+
(1, x)
|
| 165 |
+
|
| 166 |
+
See Also
|
| 167 |
+
========
|
| 168 |
+
|
| 169 |
+
MatAdd
|
| 170 |
+
|
| 171 |
+
"""
|
| 172 |
+
|
| 173 |
+
__slots__ = ()
|
| 174 |
+
|
| 175 |
+
args: tTuple[Expr, ...]
|
| 176 |
+
|
| 177 |
+
is_Add = True
|
| 178 |
+
|
| 179 |
+
_args_type = Expr
|
| 180 |
+
|
| 181 |
+
@classmethod
|
| 182 |
+
def flatten(cls, seq):
|
| 183 |
+
"""
|
| 184 |
+
Takes the sequence "seq" of nested Adds and returns a flatten list.
|
| 185 |
+
|
| 186 |
+
Returns: (commutative_part, noncommutative_part, order_symbols)
|
| 187 |
+
|
| 188 |
+
Applies associativity, all terms are commutable with respect to
|
| 189 |
+
addition.
|
| 190 |
+
|
| 191 |
+
NB: the removal of 0 is already handled by AssocOp.__new__
|
| 192 |
+
|
| 193 |
+
See Also
|
| 194 |
+
========
|
| 195 |
+
|
| 196 |
+
sympy.core.mul.Mul.flatten
|
| 197 |
+
|
| 198 |
+
"""
|
| 199 |
+
from sympy.calculus.accumulationbounds import AccumBounds
|
| 200 |
+
from sympy.matrices.expressions import MatrixExpr
|
| 201 |
+
from sympy.tensor.tensor import TensExpr
|
| 202 |
+
rv = None
|
| 203 |
+
if len(seq) == 2:
|
| 204 |
+
a, b = seq
|
| 205 |
+
if b.is_Rational:
|
| 206 |
+
a, b = b, a
|
| 207 |
+
if a.is_Rational:
|
| 208 |
+
if b.is_Mul:
|
| 209 |
+
rv = [a, b], [], None
|
| 210 |
+
if rv:
|
| 211 |
+
if all(s.is_commutative for s in rv[0]):
|
| 212 |
+
return rv
|
| 213 |
+
return [], rv[0], None
|
| 214 |
+
|
| 215 |
+
terms = {} # term -> coeff
|
| 216 |
+
# e.g. x**2 -> 5 for ... + 5*x**2 + ...
|
| 217 |
+
|
| 218 |
+
coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0
|
| 219 |
+
# e.g. 3 + ...
|
| 220 |
+
order_factors = []
|
| 221 |
+
|
| 222 |
+
extra = []
|
| 223 |
+
|
| 224 |
+
for o in seq:
|
| 225 |
+
|
| 226 |
+
# O(x)
|
| 227 |
+
if o.is_Order:
|
| 228 |
+
if o.expr.is_zero:
|
| 229 |
+
continue
|
| 230 |
+
for o1 in order_factors:
|
| 231 |
+
if o1.contains(o):
|
| 232 |
+
o = None
|
| 233 |
+
break
|
| 234 |
+
if o is None:
|
| 235 |
+
continue
|
| 236 |
+
order_factors = [o] + [
|
| 237 |
+
o1 for o1 in order_factors if not o.contains(o1)]
|
| 238 |
+
continue
|
| 239 |
+
|
| 240 |
+
# 3 or NaN
|
| 241 |
+
elif o.is_Number:
|
| 242 |
+
if (o is S.NaN or coeff is S.ComplexInfinity and
|
| 243 |
+
o.is_finite is False) and not extra:
|
| 244 |
+
# we know for sure the result will be nan
|
| 245 |
+
return [S.NaN], [], None
|
| 246 |
+
if coeff.is_Number or isinstance(coeff, AccumBounds):
|
| 247 |
+
coeff += o
|
| 248 |
+
if coeff is S.NaN and not extra:
|
| 249 |
+
# we know for sure the result will be nan
|
| 250 |
+
return [S.NaN], [], None
|
| 251 |
+
continue
|
| 252 |
+
|
| 253 |
+
elif isinstance(o, AccumBounds):
|
| 254 |
+
coeff = o.__add__(coeff)
|
| 255 |
+
continue
|
| 256 |
+
|
| 257 |
+
elif isinstance(o, MatrixExpr):
|
| 258 |
+
# can't add 0 to Matrix so make sure coeff is not 0
|
| 259 |
+
extra.append(o)
|
| 260 |
+
continue
|
| 261 |
+
|
| 262 |
+
elif isinstance(o, TensExpr):
|
| 263 |
+
coeff = o.__add__(coeff) if coeff else o
|
| 264 |
+
continue
|
| 265 |
+
|
| 266 |
+
elif o is S.ComplexInfinity:
|
| 267 |
+
if coeff.is_finite is False and not extra:
|
| 268 |
+
# we know for sure the result will be nan
|
| 269 |
+
return [S.NaN], [], None
|
| 270 |
+
coeff = S.ComplexInfinity
|
| 271 |
+
continue
|
| 272 |
+
|
| 273 |
+
# Add([...])
|
| 274 |
+
elif o.is_Add:
|
| 275 |
+
# NB: here we assume Add is always commutative
|
| 276 |
+
seq.extend(o.args) # TODO zerocopy?
|
| 277 |
+
continue
|
| 278 |
+
|
| 279 |
+
# Mul([...])
|
| 280 |
+
elif o.is_Mul:
|
| 281 |
+
c, s = o.as_coeff_Mul()
|
| 282 |
+
|
| 283 |
+
# check for unevaluated Pow, e.g. 2**3 or 2**(-1/2)
|
| 284 |
+
elif o.is_Pow:
|
| 285 |
+
b, e = o.as_base_exp()
|
| 286 |
+
if b.is_Number and (e.is_Integer or
|
| 287 |
+
(e.is_Rational and e.is_negative)):
|
| 288 |
+
seq.append(b**e)
|
| 289 |
+
continue
|
| 290 |
+
c, s = S.One, o
|
| 291 |
+
|
| 292 |
+
else:
|
| 293 |
+
# everything else
|
| 294 |
+
c = S.One
|
| 295 |
+
s = o
|
| 296 |
+
|
| 297 |
+
# now we have:
|
| 298 |
+
# o = c*s, where
|
| 299 |
+
#
|
| 300 |
+
# c is a Number
|
| 301 |
+
# s is an expression with number factor extracted
|
| 302 |
+
# let's collect terms with the same s, so e.g.
|
| 303 |
+
# 2*x**2 + 3*x**2 -> 5*x**2
|
| 304 |
+
if s in terms:
|
| 305 |
+
terms[s] += c
|
| 306 |
+
if terms[s] is S.NaN and not extra:
|
| 307 |
+
# we know for sure the result will be nan
|
| 308 |
+
return [S.NaN], [], None
|
| 309 |
+
else:
|
| 310 |
+
terms[s] = c
|
| 311 |
+
|
| 312 |
+
# now let's construct new args:
|
| 313 |
+
# [2*x**2, x**3, 7*x**4, pi, ...]
|
| 314 |
+
newseq = []
|
| 315 |
+
noncommutative = False
|
| 316 |
+
for s, c in terms.items():
|
| 317 |
+
# 0*s
|
| 318 |
+
if c.is_zero:
|
| 319 |
+
continue
|
| 320 |
+
# 1*s
|
| 321 |
+
elif c is S.One:
|
| 322 |
+
newseq.append(s)
|
| 323 |
+
# c*s
|
| 324 |
+
else:
|
| 325 |
+
if s.is_Mul:
|
| 326 |
+
# Mul, already keeps its arguments in perfect order.
|
| 327 |
+
# so we can simply put c in slot0 and go the fast way.
|
| 328 |
+
cs = s._new_rawargs(*((c,) + s.args))
|
| 329 |
+
newseq.append(cs)
|
| 330 |
+
elif s.is_Add:
|
| 331 |
+
# we just re-create the unevaluated Mul
|
| 332 |
+
newseq.append(Mul(c, s, evaluate=False))
|
| 333 |
+
else:
|
| 334 |
+
# alternatively we have to call all Mul's machinery (slow)
|
| 335 |
+
newseq.append(Mul(c, s))
|
| 336 |
+
|
| 337 |
+
noncommutative = noncommutative or not s.is_commutative
|
| 338 |
+
|
| 339 |
+
# oo, -oo
|
| 340 |
+
if coeff is S.Infinity:
|
| 341 |
+
newseq = [f for f in newseq if not (f.is_extended_nonnegative or f.is_real)]
|
| 342 |
+
|
| 343 |
+
elif coeff is S.NegativeInfinity:
|
| 344 |
+
newseq = [f for f in newseq if not (f.is_extended_nonpositive or f.is_real)]
|
| 345 |
+
|
| 346 |
+
if coeff is S.ComplexInfinity:
|
| 347 |
+
# zoo might be
|
| 348 |
+
# infinite_real + finite_im
|
| 349 |
+
# finite_real + infinite_im
|
| 350 |
+
# infinite_real + infinite_im
|
| 351 |
+
# addition of a finite real or imaginary number won't be able to
|
| 352 |
+
# change the zoo nature; adding an infinite qualtity would result
|
| 353 |
+
# in a NaN condition if it had sign opposite of the infinite
|
| 354 |
+
# portion of zoo, e.g., infinite_real - infinite_real.
|
| 355 |
+
newseq = [c for c in newseq if not (c.is_finite and
|
| 356 |
+
c.is_extended_real is not None)]
|
| 357 |
+
|
| 358 |
+
# process O(x)
|
| 359 |
+
if order_factors:
|
| 360 |
+
newseq2 = []
|
| 361 |
+
for t in newseq:
|
| 362 |
+
for o in order_factors:
|
| 363 |
+
# x + O(x) -> O(x)
|
| 364 |
+
if o.contains(t):
|
| 365 |
+
t = None
|
| 366 |
+
break
|
| 367 |
+
# x + O(x**2) -> x + O(x**2)
|
| 368 |
+
if t is not None:
|
| 369 |
+
newseq2.append(t)
|
| 370 |
+
newseq = newseq2 + order_factors
|
| 371 |
+
# 1 + O(1) -> O(1)
|
| 372 |
+
for o in order_factors:
|
| 373 |
+
if o.contains(coeff):
|
| 374 |
+
coeff = S.Zero
|
| 375 |
+
break
|
| 376 |
+
|
| 377 |
+
# order args canonically
|
| 378 |
+
_addsort(newseq)
|
| 379 |
+
|
| 380 |
+
# current code expects coeff to be first
|
| 381 |
+
if coeff is not S.Zero:
|
| 382 |
+
newseq.insert(0, coeff)
|
| 383 |
+
|
| 384 |
+
if extra:
|
| 385 |
+
newseq += extra
|
| 386 |
+
noncommutative = True
|
| 387 |
+
|
| 388 |
+
# we are done
|
| 389 |
+
if noncommutative:
|
| 390 |
+
return [], newseq, None
|
| 391 |
+
else:
|
| 392 |
+
return newseq, [], None
|
| 393 |
+
|
| 394 |
+
@classmethod
|
| 395 |
+
def class_key(cls):
|
| 396 |
+
return 3, 1, cls.__name__
|
| 397 |
+
|
| 398 |
+
@property
|
| 399 |
+
def kind(self):
|
| 400 |
+
k = attrgetter('kind')
|
| 401 |
+
kinds = map(k, self.args)
|
| 402 |
+
kinds = frozenset(kinds)
|
| 403 |
+
if len(kinds) != 1:
|
| 404 |
+
# Since addition is group operator, kind must be same.
|
| 405 |
+
# We know that this is unexpected signature, so return this.
|
| 406 |
+
result = UndefinedKind
|
| 407 |
+
else:
|
| 408 |
+
result, = kinds
|
| 409 |
+
return result
|
| 410 |
+
|
| 411 |
+
def could_extract_minus_sign(self):
|
| 412 |
+
return _could_extract_minus_sign(self)
|
| 413 |
+
|
| 414 |
+
@cacheit
|
| 415 |
+
def as_coeff_add(self, *deps):
|
| 416 |
+
"""
|
| 417 |
+
Returns a tuple (coeff, args) where self is treated as an Add and coeff
|
| 418 |
+
is the Number term and args is a tuple of all other terms.
|
| 419 |
+
|
| 420 |
+
Examples
|
| 421 |
+
========
|
| 422 |
+
|
| 423 |
+
>>> from sympy.abc import x
|
| 424 |
+
>>> (7 + 3*x).as_coeff_add()
|
| 425 |
+
(7, (3*x,))
|
| 426 |
+
>>> (7*x).as_coeff_add()
|
| 427 |
+
(0, (7*x,))
|
| 428 |
+
"""
|
| 429 |
+
if deps:
|
| 430 |
+
l1, l2 = sift(self.args, lambda x: x.has_free(*deps), binary=True)
|
| 431 |
+
return self._new_rawargs(*l2), tuple(l1)
|
| 432 |
+
coeff, notrat = self.args[0].as_coeff_add()
|
| 433 |
+
if coeff is not S.Zero:
|
| 434 |
+
return coeff, notrat + self.args[1:]
|
| 435 |
+
return S.Zero, self.args
|
| 436 |
+
|
| 437 |
+
def as_coeff_Add(self, rational=False, deps=None):
|
| 438 |
+
"""
|
| 439 |
+
Efficiently extract the coefficient of a summation.
|
| 440 |
+
"""
|
| 441 |
+
coeff, args = self.args[0], self.args[1:]
|
| 442 |
+
|
| 443 |
+
if coeff.is_Number and not rational or coeff.is_Rational:
|
| 444 |
+
return coeff, self._new_rawargs(*args)
|
| 445 |
+
return S.Zero, self
|
| 446 |
+
|
| 447 |
+
# Note, we intentionally do not implement Add.as_coeff_mul(). Rather, we
|
| 448 |
+
# let Expr.as_coeff_mul() just always return (S.One, self) for an Add. See
|
| 449 |
+
# issue 5524.
|
| 450 |
+
|
| 451 |
+
def _eval_power(self, e):
|
| 452 |
+
from .evalf import pure_complex
|
| 453 |
+
from .relational import is_eq
|
| 454 |
+
if len(self.args) == 2 and any(_.is_infinite for _ in self.args):
|
| 455 |
+
if e.is_zero is False and is_eq(e, S.One) is False:
|
| 456 |
+
# looking for literal a + I*b
|
| 457 |
+
a, b = self.args
|
| 458 |
+
if a.coeff(S.ImaginaryUnit):
|
| 459 |
+
a, b = b, a
|
| 460 |
+
ico = b.coeff(S.ImaginaryUnit)
|
| 461 |
+
if ico and ico.is_extended_real and a.is_extended_real:
|
| 462 |
+
if e.is_extended_negative:
|
| 463 |
+
return S.Zero
|
| 464 |
+
if e.is_extended_positive:
|
| 465 |
+
return S.ComplexInfinity
|
| 466 |
+
return
|
| 467 |
+
if e.is_Rational and self.is_number:
|
| 468 |
+
ri = pure_complex(self)
|
| 469 |
+
if ri:
|
| 470 |
+
r, i = ri
|
| 471 |
+
if e.q == 2:
|
| 472 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 473 |
+
D = sqrt(r**2 + i**2)
|
| 474 |
+
if D.is_Rational:
|
| 475 |
+
from .exprtools import factor_terms
|
| 476 |
+
from sympy.functions.elementary.complexes import sign
|
| 477 |
+
from .function import expand_multinomial
|
| 478 |
+
# (r, i, D) is a Pythagorean triple
|
| 479 |
+
root = sqrt(factor_terms((D - r)/2))**e.p
|
| 480 |
+
return root*expand_multinomial((
|
| 481 |
+
# principle value
|
| 482 |
+
(D + r)/abs(i) + sign(i)*S.ImaginaryUnit)**e.p)
|
| 483 |
+
elif e == -1:
|
| 484 |
+
return _unevaluated_Mul(
|
| 485 |
+
r - i*S.ImaginaryUnit,
|
| 486 |
+
1/(r**2 + i**2))
|
| 487 |
+
elif e.is_Number and abs(e) != 1:
|
| 488 |
+
# handle the Float case: (2.0 + 4*x)**e -> 4**e*(0.5 + x)**e
|
| 489 |
+
c, m = zip(*[i.as_coeff_Mul() for i in self.args])
|
| 490 |
+
if any(i.is_Float for i in c): # XXX should this always be done?
|
| 491 |
+
big = -1
|
| 492 |
+
for i in c:
|
| 493 |
+
if abs(i) >= big:
|
| 494 |
+
big = abs(i)
|
| 495 |
+
if big > 0 and not equal_valued(big, 1):
|
| 496 |
+
from sympy.functions.elementary.complexes import sign
|
| 497 |
+
bigs = (big, -big)
|
| 498 |
+
c = [sign(i) if i in bigs else i/big for i in c]
|
| 499 |
+
addpow = Add(*[c*m for c, m in zip(c, m)])**e
|
| 500 |
+
return big**e*addpow
|
| 501 |
+
|
| 502 |
+
@cacheit
|
| 503 |
+
def _eval_derivative(self, s):
|
| 504 |
+
return self.func(*[a.diff(s) for a in self.args])
|
| 505 |
+
|
| 506 |
+
def _eval_nseries(self, x, n, logx, cdir=0):
|
| 507 |
+
terms = [t.nseries(x, n=n, logx=logx, cdir=cdir) for t in self.args]
|
| 508 |
+
return self.func(*terms)
|
| 509 |
+
|
| 510 |
+
def _matches_simple(self, expr, repl_dict):
|
| 511 |
+
# handle (w+3).matches('x+5') -> {w: x+2}
|
| 512 |
+
coeff, terms = self.as_coeff_add()
|
| 513 |
+
if len(terms) == 1:
|
| 514 |
+
return terms[0].matches(expr - coeff, repl_dict)
|
| 515 |
+
return
|
| 516 |
+
|
| 517 |
+
def matches(self, expr, repl_dict=None, old=False):
|
| 518 |
+
return self._matches_commutative(expr, repl_dict, old)
|
| 519 |
+
|
| 520 |
+
@staticmethod
|
| 521 |
+
def _combine_inverse(lhs, rhs):
|
| 522 |
+
"""
|
| 523 |
+
Returns lhs - rhs, but treats oo like a symbol so oo - oo
|
| 524 |
+
returns 0, instead of a nan.
|
| 525 |
+
"""
|
| 526 |
+
from sympy.simplify.simplify import signsimp
|
| 527 |
+
inf = (S.Infinity, S.NegativeInfinity)
|
| 528 |
+
if lhs.has(*inf) or rhs.has(*inf):
|
| 529 |
+
from .symbol import Dummy
|
| 530 |
+
oo = Dummy('oo')
|
| 531 |
+
reps = {
|
| 532 |
+
S.Infinity: oo,
|
| 533 |
+
S.NegativeInfinity: -oo}
|
| 534 |
+
ireps = {v: k for k, v in reps.items()}
|
| 535 |
+
eq = lhs.xreplace(reps) - rhs.xreplace(reps)
|
| 536 |
+
if eq.has(oo):
|
| 537 |
+
eq = eq.replace(
|
| 538 |
+
lambda x: x.is_Pow and x.base is oo,
|
| 539 |
+
lambda x: x.base)
|
| 540 |
+
rv = eq.xreplace(ireps)
|
| 541 |
+
else:
|
| 542 |
+
rv = lhs - rhs
|
| 543 |
+
srv = signsimp(rv)
|
| 544 |
+
return srv if srv.is_Number else rv
|
| 545 |
+
|
| 546 |
+
@cacheit
|
| 547 |
+
def as_two_terms(self):
|
| 548 |
+
"""Return head and tail of self.
|
| 549 |
+
|
| 550 |
+
This is the most efficient way to get the head and tail of an
|
| 551 |
+
expression.
|
| 552 |
+
|
| 553 |
+
- if you want only the head, use self.args[0];
|
| 554 |
+
- if you want to process the arguments of the tail then use
|
| 555 |
+
self.as_coef_add() which gives the head and a tuple containing
|
| 556 |
+
the arguments of the tail when treated as an Add.
|
| 557 |
+
- if you want the coefficient when self is treated as a Mul
|
| 558 |
+
then use self.as_coeff_mul()[0]
|
| 559 |
+
|
| 560 |
+
>>> from sympy.abc import x, y
|
| 561 |
+
>>> (3*x - 2*y + 5).as_two_terms()
|
| 562 |
+
(5, 3*x - 2*y)
|
| 563 |
+
"""
|
| 564 |
+
return self.args[0], self._new_rawargs(*self.args[1:])
|
| 565 |
+
|
| 566 |
+
def as_numer_denom(self):
|
| 567 |
+
"""
|
| 568 |
+
Decomposes an expression to its numerator part and its
|
| 569 |
+
denominator part.
|
| 570 |
+
|
| 571 |
+
Examples
|
| 572 |
+
========
|
| 573 |
+
|
| 574 |
+
>>> from sympy.abc import x, y, z
|
| 575 |
+
>>> (x*y/z).as_numer_denom()
|
| 576 |
+
(x*y, z)
|
| 577 |
+
>>> (x*(y + 1)/y**7).as_numer_denom()
|
| 578 |
+
(x*(y + 1), y**7)
|
| 579 |
+
|
| 580 |
+
See Also
|
| 581 |
+
========
|
| 582 |
+
|
| 583 |
+
sympy.core.expr.Expr.as_numer_denom
|
| 584 |
+
"""
|
| 585 |
+
# clear rational denominator
|
| 586 |
+
content, expr = self.primitive()
|
| 587 |
+
if not isinstance(expr, Add):
|
| 588 |
+
return Mul(content, expr, evaluate=False).as_numer_denom()
|
| 589 |
+
ncon, dcon = content.as_numer_denom()
|
| 590 |
+
|
| 591 |
+
# collect numerators and denominators of the terms
|
| 592 |
+
nd = defaultdict(list)
|
| 593 |
+
for f in expr.args:
|
| 594 |
+
ni, di = f.as_numer_denom()
|
| 595 |
+
nd[di].append(ni)
|
| 596 |
+
|
| 597 |
+
# check for quick exit
|
| 598 |
+
if len(nd) == 1:
|
| 599 |
+
d, n = nd.popitem()
|
| 600 |
+
return self.func(
|
| 601 |
+
*[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d)
|
| 602 |
+
|
| 603 |
+
# sum up the terms having a common denominator
|
| 604 |
+
for d, n in nd.items():
|
| 605 |
+
if len(n) == 1:
|
| 606 |
+
nd[d] = n[0]
|
| 607 |
+
else:
|
| 608 |
+
nd[d] = self.func(*n)
|
| 609 |
+
|
| 610 |
+
# assemble single numerator and denominator
|
| 611 |
+
denoms, numers = [list(i) for i in zip(*iter(nd.items()))]
|
| 612 |
+
n, d = self.func(*[Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:]))
|
| 613 |
+
for i in range(len(numers))]), Mul(*denoms)
|
| 614 |
+
|
| 615 |
+
return _keep_coeff(ncon, n), _keep_coeff(dcon, d)
|
| 616 |
+
|
| 617 |
+
def _eval_is_polynomial(self, syms):
|
| 618 |
+
return all(term._eval_is_polynomial(syms) for term in self.args)
|
| 619 |
+
|
| 620 |
+
def _eval_is_rational_function(self, syms):
|
| 621 |
+
return all(term._eval_is_rational_function(syms) for term in self.args)
|
| 622 |
+
|
| 623 |
+
def _eval_is_meromorphic(self, x, a):
|
| 624 |
+
return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args),
|
| 625 |
+
quick_exit=True)
|
| 626 |
+
|
| 627 |
+
def _eval_is_algebraic_expr(self, syms):
|
| 628 |
+
return all(term._eval_is_algebraic_expr(syms) for term in self.args)
|
| 629 |
+
|
| 630 |
+
# assumption methods
|
| 631 |
+
_eval_is_real = lambda self: _fuzzy_group(
|
| 632 |
+
(a.is_real for a in self.args), quick_exit=True)
|
| 633 |
+
_eval_is_extended_real = lambda self: _fuzzy_group(
|
| 634 |
+
(a.is_extended_real for a in self.args), quick_exit=True)
|
| 635 |
+
_eval_is_complex = lambda self: _fuzzy_group(
|
| 636 |
+
(a.is_complex for a in self.args), quick_exit=True)
|
| 637 |
+
_eval_is_antihermitian = lambda self: _fuzzy_group(
|
| 638 |
+
(a.is_antihermitian for a in self.args), quick_exit=True)
|
| 639 |
+
_eval_is_finite = lambda self: _fuzzy_group(
|
| 640 |
+
(a.is_finite for a in self.args), quick_exit=True)
|
| 641 |
+
_eval_is_hermitian = lambda self: _fuzzy_group(
|
| 642 |
+
(a.is_hermitian for a in self.args), quick_exit=True)
|
| 643 |
+
_eval_is_integer = lambda self: _fuzzy_group(
|
| 644 |
+
(a.is_integer for a in self.args), quick_exit=True)
|
| 645 |
+
_eval_is_rational = lambda self: _fuzzy_group(
|
| 646 |
+
(a.is_rational for a in self.args), quick_exit=True)
|
| 647 |
+
_eval_is_algebraic = lambda self: _fuzzy_group(
|
| 648 |
+
(a.is_algebraic for a in self.args), quick_exit=True)
|
| 649 |
+
_eval_is_commutative = lambda self: _fuzzy_group(
|
| 650 |
+
a.is_commutative for a in self.args)
|
| 651 |
+
|
| 652 |
+
def _eval_is_infinite(self):
|
| 653 |
+
sawinf = False
|
| 654 |
+
for a in self.args:
|
| 655 |
+
ainf = a.is_infinite
|
| 656 |
+
if ainf is None:
|
| 657 |
+
return None
|
| 658 |
+
elif ainf is True:
|
| 659 |
+
# infinite+infinite might not be infinite
|
| 660 |
+
if sawinf is True:
|
| 661 |
+
return None
|
| 662 |
+
sawinf = True
|
| 663 |
+
return sawinf
|
| 664 |
+
|
| 665 |
+
def _eval_is_imaginary(self):
|
| 666 |
+
nz = []
|
| 667 |
+
im_I = []
|
| 668 |
+
for a in self.args:
|
| 669 |
+
if a.is_extended_real:
|
| 670 |
+
if a.is_zero:
|
| 671 |
+
pass
|
| 672 |
+
elif a.is_zero is False:
|
| 673 |
+
nz.append(a)
|
| 674 |
+
else:
|
| 675 |
+
return
|
| 676 |
+
elif a.is_imaginary:
|
| 677 |
+
im_I.append(a*S.ImaginaryUnit)
|
| 678 |
+
elif a.is_Mul and S.ImaginaryUnit in a.args:
|
| 679 |
+
coeff, ai = a.as_coeff_mul(S.ImaginaryUnit)
|
| 680 |
+
if ai == (S.ImaginaryUnit,) and coeff.is_extended_real:
|
| 681 |
+
im_I.append(-coeff)
|
| 682 |
+
else:
|
| 683 |
+
return
|
| 684 |
+
else:
|
| 685 |
+
return
|
| 686 |
+
b = self.func(*nz)
|
| 687 |
+
if b != self:
|
| 688 |
+
if b.is_zero:
|
| 689 |
+
return fuzzy_not(self.func(*im_I).is_zero)
|
| 690 |
+
elif b.is_zero is False:
|
| 691 |
+
return False
|
| 692 |
+
|
| 693 |
+
def _eval_is_zero(self):
|
| 694 |
+
if self.is_commutative is False:
|
| 695 |
+
# issue 10528: there is no way to know if a nc symbol
|
| 696 |
+
# is zero or not
|
| 697 |
+
return
|
| 698 |
+
nz = []
|
| 699 |
+
z = 0
|
| 700 |
+
im_or_z = False
|
| 701 |
+
im = 0
|
| 702 |
+
for a in self.args:
|
| 703 |
+
if a.is_extended_real:
|
| 704 |
+
if a.is_zero:
|
| 705 |
+
z += 1
|
| 706 |
+
elif a.is_zero is False:
|
| 707 |
+
nz.append(a)
|
| 708 |
+
else:
|
| 709 |
+
return
|
| 710 |
+
elif a.is_imaginary:
|
| 711 |
+
im += 1
|
| 712 |
+
elif a.is_Mul and S.ImaginaryUnit in a.args:
|
| 713 |
+
coeff, ai = a.as_coeff_mul(S.ImaginaryUnit)
|
| 714 |
+
if ai == (S.ImaginaryUnit,) and coeff.is_extended_real:
|
| 715 |
+
im_or_z = True
|
| 716 |
+
else:
|
| 717 |
+
return
|
| 718 |
+
else:
|
| 719 |
+
return
|
| 720 |
+
if z == len(self.args):
|
| 721 |
+
return True
|
| 722 |
+
if len(nz) in [0, len(self.args)]:
|
| 723 |
+
return None
|
| 724 |
+
b = self.func(*nz)
|
| 725 |
+
if b.is_zero:
|
| 726 |
+
if not im_or_z:
|
| 727 |
+
if im == 0:
|
| 728 |
+
return True
|
| 729 |
+
elif im == 1:
|
| 730 |
+
return False
|
| 731 |
+
if b.is_zero is False:
|
| 732 |
+
return False
|
| 733 |
+
|
| 734 |
+
def _eval_is_odd(self):
|
| 735 |
+
l = [f for f in self.args if not (f.is_even is True)]
|
| 736 |
+
if not l:
|
| 737 |
+
return False
|
| 738 |
+
if l[0].is_odd:
|
| 739 |
+
return self._new_rawargs(*l[1:]).is_even
|
| 740 |
+
|
| 741 |
+
def _eval_is_irrational(self):
|
| 742 |
+
for t in self.args:
|
| 743 |
+
a = t.is_irrational
|
| 744 |
+
if a:
|
| 745 |
+
others = list(self.args)
|
| 746 |
+
others.remove(t)
|
| 747 |
+
if all(x.is_rational is True for x in others):
|
| 748 |
+
return True
|
| 749 |
+
return None
|
| 750 |
+
if a is None:
|
| 751 |
+
return
|
| 752 |
+
return False
|
| 753 |
+
|
| 754 |
+
def _all_nonneg_or_nonppos(self):
|
| 755 |
+
nn = np = 0
|
| 756 |
+
for a in self.args:
|
| 757 |
+
if a.is_nonnegative:
|
| 758 |
+
if np:
|
| 759 |
+
return False
|
| 760 |
+
nn = 1
|
| 761 |
+
elif a.is_nonpositive:
|
| 762 |
+
if nn:
|
| 763 |
+
return False
|
| 764 |
+
np = 1
|
| 765 |
+
else:
|
| 766 |
+
break
|
| 767 |
+
else:
|
| 768 |
+
return True
|
| 769 |
+
|
| 770 |
+
def _eval_is_extended_positive(self):
|
| 771 |
+
if self.is_number:
|
| 772 |
+
return super()._eval_is_extended_positive()
|
| 773 |
+
c, a = self.as_coeff_Add()
|
| 774 |
+
if not c.is_zero:
|
| 775 |
+
from .exprtools import _monotonic_sign
|
| 776 |
+
v = _monotonic_sign(a)
|
| 777 |
+
if v is not None:
|
| 778 |
+
s = v + c
|
| 779 |
+
if s != self and s.is_extended_positive and a.is_extended_nonnegative:
|
| 780 |
+
return True
|
| 781 |
+
if len(self.free_symbols) == 1:
|
| 782 |
+
v = _monotonic_sign(self)
|
| 783 |
+
if v is not None and v != self and v.is_extended_positive:
|
| 784 |
+
return True
|
| 785 |
+
pos = nonneg = nonpos = unknown_sign = False
|
| 786 |
+
saw_INF = set()
|
| 787 |
+
args = [a for a in self.args if not a.is_zero]
|
| 788 |
+
if not args:
|
| 789 |
+
return False
|
| 790 |
+
for a in args:
|
| 791 |
+
ispos = a.is_extended_positive
|
| 792 |
+
infinite = a.is_infinite
|
| 793 |
+
if infinite:
|
| 794 |
+
saw_INF.add(fuzzy_or((ispos, a.is_extended_nonnegative)))
|
| 795 |
+
if True in saw_INF and False in saw_INF:
|
| 796 |
+
return
|
| 797 |
+
if ispos:
|
| 798 |
+
pos = True
|
| 799 |
+
continue
|
| 800 |
+
elif a.is_extended_nonnegative:
|
| 801 |
+
nonneg = True
|
| 802 |
+
continue
|
| 803 |
+
elif a.is_extended_nonpositive:
|
| 804 |
+
nonpos = True
|
| 805 |
+
continue
|
| 806 |
+
|
| 807 |
+
if infinite is None:
|
| 808 |
+
return
|
| 809 |
+
unknown_sign = True
|
| 810 |
+
|
| 811 |
+
if saw_INF:
|
| 812 |
+
if len(saw_INF) > 1:
|
| 813 |
+
return
|
| 814 |
+
return saw_INF.pop()
|
| 815 |
+
elif unknown_sign:
|
| 816 |
+
return
|
| 817 |
+
elif not nonpos and not nonneg and pos:
|
| 818 |
+
return True
|
| 819 |
+
elif not nonpos and pos:
|
| 820 |
+
return True
|
| 821 |
+
elif not pos and not nonneg:
|
| 822 |
+
return False
|
| 823 |
+
|
| 824 |
+
def _eval_is_extended_nonnegative(self):
|
| 825 |
+
if not self.is_number:
|
| 826 |
+
c, a = self.as_coeff_Add()
|
| 827 |
+
if not c.is_zero and a.is_extended_nonnegative:
|
| 828 |
+
from .exprtools import _monotonic_sign
|
| 829 |
+
v = _monotonic_sign(a)
|
| 830 |
+
if v is not None:
|
| 831 |
+
s = v + c
|
| 832 |
+
if s != self and s.is_extended_nonnegative:
|
| 833 |
+
return True
|
| 834 |
+
if len(self.free_symbols) == 1:
|
| 835 |
+
v = _monotonic_sign(self)
|
| 836 |
+
if v is not None and v != self and v.is_extended_nonnegative:
|
| 837 |
+
return True
|
| 838 |
+
|
| 839 |
+
def _eval_is_extended_nonpositive(self):
|
| 840 |
+
if not self.is_number:
|
| 841 |
+
c, a = self.as_coeff_Add()
|
| 842 |
+
if not c.is_zero and a.is_extended_nonpositive:
|
| 843 |
+
from .exprtools import _monotonic_sign
|
| 844 |
+
v = _monotonic_sign(a)
|
| 845 |
+
if v is not None:
|
| 846 |
+
s = v + c
|
| 847 |
+
if s != self and s.is_extended_nonpositive:
|
| 848 |
+
return True
|
| 849 |
+
if len(self.free_symbols) == 1:
|
| 850 |
+
v = _monotonic_sign(self)
|
| 851 |
+
if v is not None and v != self and v.is_extended_nonpositive:
|
| 852 |
+
return True
|
| 853 |
+
|
| 854 |
+
def _eval_is_extended_negative(self):
|
| 855 |
+
if self.is_number:
|
| 856 |
+
return super()._eval_is_extended_negative()
|
| 857 |
+
c, a = self.as_coeff_Add()
|
| 858 |
+
if not c.is_zero:
|
| 859 |
+
from .exprtools import _monotonic_sign
|
| 860 |
+
v = _monotonic_sign(a)
|
| 861 |
+
if v is not None:
|
| 862 |
+
s = v + c
|
| 863 |
+
if s != self and s.is_extended_negative and a.is_extended_nonpositive:
|
| 864 |
+
return True
|
| 865 |
+
if len(self.free_symbols) == 1:
|
| 866 |
+
v = _monotonic_sign(self)
|
| 867 |
+
if v is not None and v != self and v.is_extended_negative:
|
| 868 |
+
return True
|
| 869 |
+
neg = nonpos = nonneg = unknown_sign = False
|
| 870 |
+
saw_INF = set()
|
| 871 |
+
args = [a for a in self.args if not a.is_zero]
|
| 872 |
+
if not args:
|
| 873 |
+
return False
|
| 874 |
+
for a in args:
|
| 875 |
+
isneg = a.is_extended_negative
|
| 876 |
+
infinite = a.is_infinite
|
| 877 |
+
if infinite:
|
| 878 |
+
saw_INF.add(fuzzy_or((isneg, a.is_extended_nonpositive)))
|
| 879 |
+
if True in saw_INF and False in saw_INF:
|
| 880 |
+
return
|
| 881 |
+
if isneg:
|
| 882 |
+
neg = True
|
| 883 |
+
continue
|
| 884 |
+
elif a.is_extended_nonpositive:
|
| 885 |
+
nonpos = True
|
| 886 |
+
continue
|
| 887 |
+
elif a.is_extended_nonnegative:
|
| 888 |
+
nonneg = True
|
| 889 |
+
continue
|
| 890 |
+
|
| 891 |
+
if infinite is None:
|
| 892 |
+
return
|
| 893 |
+
unknown_sign = True
|
| 894 |
+
|
| 895 |
+
if saw_INF:
|
| 896 |
+
if len(saw_INF) > 1:
|
| 897 |
+
return
|
| 898 |
+
return saw_INF.pop()
|
| 899 |
+
elif unknown_sign:
|
| 900 |
+
return
|
| 901 |
+
elif not nonneg and not nonpos and neg:
|
| 902 |
+
return True
|
| 903 |
+
elif not nonneg and neg:
|
| 904 |
+
return True
|
| 905 |
+
elif not neg and not nonpos:
|
| 906 |
+
return False
|
| 907 |
+
|
| 908 |
+
def _eval_subs(self, old, new):
|
| 909 |
+
if not old.is_Add:
|
| 910 |
+
if old is S.Infinity and -old in self.args:
|
| 911 |
+
# foo - oo is foo + (-oo) internally
|
| 912 |
+
return self.xreplace({-old: -new})
|
| 913 |
+
return None
|
| 914 |
+
|
| 915 |
+
coeff_self, terms_self = self.as_coeff_Add()
|
| 916 |
+
coeff_old, terms_old = old.as_coeff_Add()
|
| 917 |
+
|
| 918 |
+
if coeff_self.is_Rational and coeff_old.is_Rational:
|
| 919 |
+
if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y
|
| 920 |
+
return self.func(new, coeff_self, -coeff_old)
|
| 921 |
+
if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y
|
| 922 |
+
return self.func(-new, coeff_self, coeff_old)
|
| 923 |
+
|
| 924 |
+
if coeff_self.is_Rational and coeff_old.is_Rational \
|
| 925 |
+
or coeff_self == coeff_old:
|
| 926 |
+
args_old, args_self = self.func.make_args(
|
| 927 |
+
terms_old), self.func.make_args(terms_self)
|
| 928 |
+
if len(args_old) < len(args_self): # (a+b+c).subs(b+c,x) -> a+x
|
| 929 |
+
self_set = set(args_self)
|
| 930 |
+
old_set = set(args_old)
|
| 931 |
+
|
| 932 |
+
if old_set < self_set:
|
| 933 |
+
ret_set = self_set - old_set
|
| 934 |
+
return self.func(new, coeff_self, -coeff_old,
|
| 935 |
+
*[s._subs(old, new) for s in ret_set])
|
| 936 |
+
|
| 937 |
+
args_old = self.func.make_args(
|
| 938 |
+
-terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d
|
| 939 |
+
old_set = set(args_old)
|
| 940 |
+
if old_set < self_set:
|
| 941 |
+
ret_set = self_set - old_set
|
| 942 |
+
return self.func(-new, coeff_self, coeff_old,
|
| 943 |
+
*[s._subs(old, new) for s in ret_set])
|
| 944 |
+
|
| 945 |
+
def removeO(self):
|
| 946 |
+
args = [a for a in self.args if not a.is_Order]
|
| 947 |
+
return self._new_rawargs(*args)
|
| 948 |
+
|
| 949 |
+
def getO(self):
|
| 950 |
+
args = [a for a in self.args if a.is_Order]
|
| 951 |
+
if args:
|
| 952 |
+
return self._new_rawargs(*args)
|
| 953 |
+
|
| 954 |
+
@cacheit
|
| 955 |
+
def extract_leading_order(self, symbols, point=None):
|
| 956 |
+
"""
|
| 957 |
+
Returns the leading term and its order.
|
| 958 |
+
|
| 959 |
+
Examples
|
| 960 |
+
========
|
| 961 |
+
|
| 962 |
+
>>> from sympy.abc import x
|
| 963 |
+
>>> (x + 1 + 1/x**5).extract_leading_order(x)
|
| 964 |
+
((x**(-5), O(x**(-5))),)
|
| 965 |
+
>>> (1 + x).extract_leading_order(x)
|
| 966 |
+
((1, O(1)),)
|
| 967 |
+
>>> (x + x**2).extract_leading_order(x)
|
| 968 |
+
((x, O(x)),)
|
| 969 |
+
|
| 970 |
+
"""
|
| 971 |
+
from sympy.series.order import Order
|
| 972 |
+
lst = []
|
| 973 |
+
symbols = list(symbols if is_sequence(symbols) else [symbols])
|
| 974 |
+
if not point:
|
| 975 |
+
point = [0]*len(symbols)
|
| 976 |
+
seq = [(f, Order(f, *zip(symbols, point))) for f in self.args]
|
| 977 |
+
for ef, of in seq:
|
| 978 |
+
for e, o in lst:
|
| 979 |
+
if o.contains(of) and o != of:
|
| 980 |
+
of = None
|
| 981 |
+
break
|
| 982 |
+
if of is None:
|
| 983 |
+
continue
|
| 984 |
+
new_lst = [(ef, of)]
|
| 985 |
+
for e, o in lst:
|
| 986 |
+
if of.contains(o) and o != of:
|
| 987 |
+
continue
|
| 988 |
+
new_lst.append((e, o))
|
| 989 |
+
lst = new_lst
|
| 990 |
+
return tuple(lst)
|
| 991 |
+
|
| 992 |
+
def as_real_imag(self, deep=True, **hints):
|
| 993 |
+
"""
|
| 994 |
+
Return a tuple representing a complex number.
|
| 995 |
+
|
| 996 |
+
Examples
|
| 997 |
+
========
|
| 998 |
+
|
| 999 |
+
>>> from sympy import I
|
| 1000 |
+
>>> (7 + 9*I).as_real_imag()
|
| 1001 |
+
(7, 9)
|
| 1002 |
+
>>> ((1 + I)/(1 - I)).as_real_imag()
|
| 1003 |
+
(0, 1)
|
| 1004 |
+
>>> ((1 + 2*I)*(1 + 3*I)).as_real_imag()
|
| 1005 |
+
(-5, 5)
|
| 1006 |
+
"""
|
| 1007 |
+
sargs = self.args
|
| 1008 |
+
re_part, im_part = [], []
|
| 1009 |
+
for term in sargs:
|
| 1010 |
+
re, im = term.as_real_imag(deep=deep)
|
| 1011 |
+
re_part.append(re)
|
| 1012 |
+
im_part.append(im)
|
| 1013 |
+
return (self.func(*re_part), self.func(*im_part))
|
| 1014 |
+
|
| 1015 |
+
def _eval_as_leading_term(self, x, logx=None, cdir=0):
|
| 1016 |
+
from sympy.core.symbol import Dummy, Symbol
|
| 1017 |
+
from sympy.series.order import Order
|
| 1018 |
+
from sympy.functions.elementary.exponential import log
|
| 1019 |
+
from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
|
| 1020 |
+
from .function import expand_mul
|
| 1021 |
+
|
| 1022 |
+
o = self.getO()
|
| 1023 |
+
if o is None:
|
| 1024 |
+
o = Order(0)
|
| 1025 |
+
old = self.removeO()
|
| 1026 |
+
|
| 1027 |
+
if old.has(Piecewise):
|
| 1028 |
+
old = piecewise_fold(old)
|
| 1029 |
+
|
| 1030 |
+
# This expansion is the last part of expand_log. expand_log also calls
|
| 1031 |
+
# expand_mul with factor=True, which would be more expensive
|
| 1032 |
+
if any(isinstance(a, log) for a in self.args):
|
| 1033 |
+
logflags = {"deep": True, "log": True, "mul": False, "power_exp": False,
|
| 1034 |
+
"power_base": False, "multinomial": False, "basic": False, "force": False,
|
| 1035 |
+
"factor": False}
|
| 1036 |
+
old = old.expand(**logflags)
|
| 1037 |
+
expr = expand_mul(old)
|
| 1038 |
+
|
| 1039 |
+
if not expr.is_Add:
|
| 1040 |
+
return expr.as_leading_term(x, logx=logx, cdir=cdir)
|
| 1041 |
+
|
| 1042 |
+
infinite = [t for t in expr.args if t.is_infinite]
|
| 1043 |
+
|
| 1044 |
+
_logx = Dummy('logx') if logx is None else logx
|
| 1045 |
+
leading_terms = [t.as_leading_term(x, logx=_logx, cdir=cdir) for t in expr.args]
|
| 1046 |
+
|
| 1047 |
+
min, new_expr = Order(0), 0
|
| 1048 |
+
|
| 1049 |
+
try:
|
| 1050 |
+
for term in leading_terms:
|
| 1051 |
+
order = Order(term, x)
|
| 1052 |
+
if not min or order not in min:
|
| 1053 |
+
min = order
|
| 1054 |
+
new_expr = term
|
| 1055 |
+
elif min in order:
|
| 1056 |
+
new_expr += term
|
| 1057 |
+
|
| 1058 |
+
except TypeError:
|
| 1059 |
+
return expr
|
| 1060 |
+
|
| 1061 |
+
if logx is None:
|
| 1062 |
+
new_expr = new_expr.subs(_logx, log(x))
|
| 1063 |
+
|
| 1064 |
+
is_zero = new_expr.is_zero
|
| 1065 |
+
if is_zero is None:
|
| 1066 |
+
new_expr = new_expr.trigsimp().cancel()
|
| 1067 |
+
is_zero = new_expr.is_zero
|
| 1068 |
+
if is_zero is True:
|
| 1069 |
+
# simple leading term analysis gave us cancelled terms but we have to send
|
| 1070 |
+
# back a term, so compute the leading term (via series)
|
| 1071 |
+
try:
|
| 1072 |
+
n0 = min.getn()
|
| 1073 |
+
except NotImplementedError:
|
| 1074 |
+
n0 = S.One
|
| 1075 |
+
if n0.has(Symbol):
|
| 1076 |
+
n0 = S.One
|
| 1077 |
+
res = Order(1)
|
| 1078 |
+
incr = S.One
|
| 1079 |
+
while res.is_Order:
|
| 1080 |
+
res = old._eval_nseries(x, n=n0+incr, logx=logx, cdir=cdir).cancel().powsimp().trigsimp()
|
| 1081 |
+
incr *= 2
|
| 1082 |
+
return res.as_leading_term(x, logx=logx, cdir=cdir)
|
| 1083 |
+
|
| 1084 |
+
elif new_expr is S.NaN:
|
| 1085 |
+
return old.func._from_args(infinite) + o
|
| 1086 |
+
|
| 1087 |
+
else:
|
| 1088 |
+
return new_expr
|
| 1089 |
+
|
| 1090 |
+
def _eval_adjoint(self):
|
| 1091 |
+
return self.func(*[t.adjoint() for t in self.args])
|
| 1092 |
+
|
| 1093 |
+
def _eval_conjugate(self):
|
| 1094 |
+
return self.func(*[t.conjugate() for t in self.args])
|
| 1095 |
+
|
| 1096 |
+
def _eval_transpose(self):
|
| 1097 |
+
return self.func(*[t.transpose() for t in self.args])
|
| 1098 |
+
|
| 1099 |
+
def primitive(self):
|
| 1100 |
+
"""
|
| 1101 |
+
Return ``(R, self/R)`` where ``R``` is the Rational GCD of ``self```.
|
| 1102 |
+
|
| 1103 |
+
``R`` is collected only from the leading coefficient of each term.
|
| 1104 |
+
|
| 1105 |
+
Examples
|
| 1106 |
+
========
|
| 1107 |
+
|
| 1108 |
+
>>> from sympy.abc import x, y
|
| 1109 |
+
|
| 1110 |
+
>>> (2*x + 4*y).primitive()
|
| 1111 |
+
(2, x + 2*y)
|
| 1112 |
+
|
| 1113 |
+
>>> (2*x/3 + 4*y/9).primitive()
|
| 1114 |
+
(2/9, 3*x + 2*y)
|
| 1115 |
+
|
| 1116 |
+
>>> (2*x/3 + 4.2*y).primitive()
|
| 1117 |
+
(1/3, 2*x + 12.6*y)
|
| 1118 |
+
|
| 1119 |
+
No subprocessing of term factors is performed:
|
| 1120 |
+
|
| 1121 |
+
>>> ((2 + 2*x)*x + 2).primitive()
|
| 1122 |
+
(1, x*(2*x + 2) + 2)
|
| 1123 |
+
|
| 1124 |
+
Recursive processing can be done with the ``as_content_primitive()``
|
| 1125 |
+
method:
|
| 1126 |
+
|
| 1127 |
+
>>> ((2 + 2*x)*x + 2).as_content_primitive()
|
| 1128 |
+
(2, x*(x + 1) + 1)
|
| 1129 |
+
|
| 1130 |
+
See also: primitive() function in polytools.py
|
| 1131 |
+
|
| 1132 |
+
"""
|
| 1133 |
+
|
| 1134 |
+
terms = []
|
| 1135 |
+
inf = False
|
| 1136 |
+
for a in self.args:
|
| 1137 |
+
c, m = a.as_coeff_Mul()
|
| 1138 |
+
if not c.is_Rational:
|
| 1139 |
+
c = S.One
|
| 1140 |
+
m = a
|
| 1141 |
+
inf = inf or m is S.ComplexInfinity
|
| 1142 |
+
terms.append((c.p, c.q, m))
|
| 1143 |
+
|
| 1144 |
+
if not inf:
|
| 1145 |
+
ngcd = reduce(igcd, [t[0] for t in terms], 0)
|
| 1146 |
+
dlcm = reduce(ilcm, [t[1] for t in terms], 1)
|
| 1147 |
+
else:
|
| 1148 |
+
ngcd = reduce(igcd, [t[0] for t in terms if t[1]], 0)
|
| 1149 |
+
dlcm = reduce(ilcm, [t[1] for t in terms if t[1]], 1)
|
| 1150 |
+
|
| 1151 |
+
if ngcd == dlcm == 1:
|
| 1152 |
+
return S.One, self
|
| 1153 |
+
if not inf:
|
| 1154 |
+
for i, (p, q, term) in enumerate(terms):
|
| 1155 |
+
terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term)
|
| 1156 |
+
else:
|
| 1157 |
+
for i, (p, q, term) in enumerate(terms):
|
| 1158 |
+
if q:
|
| 1159 |
+
terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term)
|
| 1160 |
+
else:
|
| 1161 |
+
terms[i] = _keep_coeff(Rational(p, q), term)
|
| 1162 |
+
|
| 1163 |
+
# we don't need a complete re-flattening since no new terms will join
|
| 1164 |
+
# so we just use the same sort as is used in Add.flatten. When the
|
| 1165 |
+
# coefficient changes, the ordering of terms may change, e.g.
|
| 1166 |
+
# (3*x, 6*y) -> (2*y, x)
|
| 1167 |
+
#
|
| 1168 |
+
# We do need to make sure that term[0] stays in position 0, however.
|
| 1169 |
+
#
|
| 1170 |
+
if terms[0].is_Number or terms[0] is S.ComplexInfinity:
|
| 1171 |
+
c = terms.pop(0)
|
| 1172 |
+
else:
|
| 1173 |
+
c = None
|
| 1174 |
+
_addsort(terms)
|
| 1175 |
+
if c:
|
| 1176 |
+
terms.insert(0, c)
|
| 1177 |
+
return Rational(ngcd, dlcm), self._new_rawargs(*terms)
|
| 1178 |
+
|
| 1179 |
+
def as_content_primitive(self, radical=False, clear=True):
|
| 1180 |
+
"""Return the tuple (R, self/R) where R is the positive Rational
|
| 1181 |
+
extracted from self. If radical is True (default is False) then
|
| 1182 |
+
common radicals will be removed and included as a factor of the
|
| 1183 |
+
primitive expression.
|
| 1184 |
+
|
| 1185 |
+
Examples
|
| 1186 |
+
========
|
| 1187 |
+
|
| 1188 |
+
>>> from sympy import sqrt
|
| 1189 |
+
>>> (3 + 3*sqrt(2)).as_content_primitive()
|
| 1190 |
+
(3, 1 + sqrt(2))
|
| 1191 |
+
|
| 1192 |
+
Radical content can also be factored out of the primitive:
|
| 1193 |
+
|
| 1194 |
+
>>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True)
|
| 1195 |
+
(2, sqrt(2)*(1 + 2*sqrt(5)))
|
| 1196 |
+
|
| 1197 |
+
See docstring of Expr.as_content_primitive for more examples.
|
| 1198 |
+
"""
|
| 1199 |
+
con, prim = self.func(*[_keep_coeff(*a.as_content_primitive(
|
| 1200 |
+
radical=radical, clear=clear)) for a in self.args]).primitive()
|
| 1201 |
+
if not clear and not con.is_Integer and prim.is_Add:
|
| 1202 |
+
con, d = con.as_numer_denom()
|
| 1203 |
+
_p = prim/d
|
| 1204 |
+
if any(a.as_coeff_Mul()[0].is_Integer for a in _p.args):
|
| 1205 |
+
prim = _p
|
| 1206 |
+
else:
|
| 1207 |
+
con /= d
|
| 1208 |
+
if radical and prim.is_Add:
|
| 1209 |
+
# look for common radicals that can be removed
|
| 1210 |
+
args = prim.args
|
| 1211 |
+
rads = []
|
| 1212 |
+
common_q = None
|
| 1213 |
+
for m in args:
|
| 1214 |
+
term_rads = defaultdict(list)
|
| 1215 |
+
for ai in Mul.make_args(m):
|
| 1216 |
+
if ai.is_Pow:
|
| 1217 |
+
b, e = ai.as_base_exp()
|
| 1218 |
+
if e.is_Rational and b.is_Integer:
|
| 1219 |
+
term_rads[e.q].append(abs(int(b))**e.p)
|
| 1220 |
+
if not term_rads:
|
| 1221 |
+
break
|
| 1222 |
+
if common_q is None:
|
| 1223 |
+
common_q = set(term_rads.keys())
|
| 1224 |
+
else:
|
| 1225 |
+
common_q = common_q & set(term_rads.keys())
|
| 1226 |
+
if not common_q:
|
| 1227 |
+
break
|
| 1228 |
+
rads.append(term_rads)
|
| 1229 |
+
else:
|
| 1230 |
+
# process rads
|
| 1231 |
+
# keep only those in common_q
|
| 1232 |
+
for r in rads:
|
| 1233 |
+
for q in list(r.keys()):
|
| 1234 |
+
if q not in common_q:
|
| 1235 |
+
r.pop(q)
|
| 1236 |
+
for q in r:
|
| 1237 |
+
r[q] = Mul(*r[q])
|
| 1238 |
+
# find the gcd of bases for each q
|
| 1239 |
+
G = []
|
| 1240 |
+
for q in common_q:
|
| 1241 |
+
g = reduce(igcd, [r[q] for r in rads], 0)
|
| 1242 |
+
if g != 1:
|
| 1243 |
+
G.append(g**Rational(1, q))
|
| 1244 |
+
if G:
|
| 1245 |
+
G = Mul(*G)
|
| 1246 |
+
args = [ai/G for ai in args]
|
| 1247 |
+
prim = G*prim.func(*args)
|
| 1248 |
+
|
| 1249 |
+
return con, prim
|
| 1250 |
+
|
| 1251 |
+
@property
|
| 1252 |
+
def _sorted_args(self):
|
| 1253 |
+
from .sorting import default_sort_key
|
| 1254 |
+
return tuple(sorted(self.args, key=default_sort_key))
|
| 1255 |
+
|
| 1256 |
+
def _eval_difference_delta(self, n, step):
|
| 1257 |
+
from sympy.series.limitseq import difference_delta as dd
|
| 1258 |
+
return self.func(*[dd(a, n, step) for a in self.args])
|
| 1259 |
+
|
| 1260 |
+
@property
|
| 1261 |
+
def _mpc_(self):
|
| 1262 |
+
"""
|
| 1263 |
+
Convert self to an mpmath mpc if possible
|
| 1264 |
+
"""
|
| 1265 |
+
from .numbers import Float
|
| 1266 |
+
re_part, rest = self.as_coeff_Add()
|
| 1267 |
+
im_part, imag_unit = rest.as_coeff_Mul()
|
| 1268 |
+
if not imag_unit == S.ImaginaryUnit:
|
| 1269 |
+
# ValueError may seem more reasonable but since it's a @property,
|
| 1270 |
+
# we need to use AttributeError to keep from confusing things like
|
| 1271 |
+
# hasattr.
|
| 1272 |
+
raise AttributeError("Cannot convert Add to mpc. Must be of the form Number + Number*I")
|
| 1273 |
+
|
| 1274 |
+
return (Float(re_part)._mpf_, Float(im_part)._mpf_)
|
| 1275 |
+
|
| 1276 |
+
def __neg__(self):
|
| 1277 |
+
if not global_parameters.distribute:
|
| 1278 |
+
return super().__neg__()
|
| 1279 |
+
return Mul(S.NegativeOne, self)
|
| 1280 |
+
|
| 1281 |
+
add = AssocOpDispatcher('add')
|
| 1282 |
+
|
| 1283 |
+
from .mul import Mul, _keep_coeff, _unevaluated_Mul
|
| 1284 |
+
from .numbers import Rational
|
lib/python3.12/site-packages/sympy/core/alphabets.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
greeks = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta',
|
| 2 |
+
'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu',
|
| 3 |
+
'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon',
|
| 4 |
+
'phi', 'chi', 'psi', 'omega')
|
lib/python3.12/site-packages/sympy/core/assumptions.py
ADDED
|
@@ -0,0 +1,692 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module contains the machinery handling assumptions.
|
| 3 |
+
Do also consider the guide :ref:`assumptions-guide`.
|
| 4 |
+
|
| 5 |
+
All symbolic objects have assumption attributes that can be accessed via
|
| 6 |
+
``.is_<assumption name>`` attribute.
|
| 7 |
+
|
| 8 |
+
Assumptions determine certain properties of symbolic objects and can
|
| 9 |
+
have 3 possible values: ``True``, ``False``, ``None``. ``True`` is returned if the
|
| 10 |
+
object has the property and ``False`` is returned if it does not or cannot
|
| 11 |
+
(i.e. does not make sense):
|
| 12 |
+
|
| 13 |
+
>>> from sympy import I
|
| 14 |
+
>>> I.is_algebraic
|
| 15 |
+
True
|
| 16 |
+
>>> I.is_real
|
| 17 |
+
False
|
| 18 |
+
>>> I.is_prime
|
| 19 |
+
False
|
| 20 |
+
|
| 21 |
+
When the property cannot be determined (or when a method is not
|
| 22 |
+
implemented) ``None`` will be returned. For example, a generic symbol, ``x``,
|
| 23 |
+
may or may not be positive so a value of ``None`` is returned for ``x.is_positive``.
|
| 24 |
+
|
| 25 |
+
By default, all symbolic values are in the largest set in the given context
|
| 26 |
+
without specifying the property. For example, a symbol that has a property
|
| 27 |
+
being integer, is also real, complex, etc.
|
| 28 |
+
|
| 29 |
+
Here follows a list of possible assumption names:
|
| 30 |
+
|
| 31 |
+
.. glossary::
|
| 32 |
+
|
| 33 |
+
commutative
|
| 34 |
+
object commutes with any other object with
|
| 35 |
+
respect to multiplication operation. See [12]_.
|
| 36 |
+
|
| 37 |
+
complex
|
| 38 |
+
object can have only values from the set
|
| 39 |
+
of complex numbers. See [13]_.
|
| 40 |
+
|
| 41 |
+
imaginary
|
| 42 |
+
object value is a number that can be written as a real
|
| 43 |
+
number multiplied by the imaginary unit ``I``. See
|
| 44 |
+
[3]_. Please note that ``0`` is not considered to be an
|
| 45 |
+
imaginary number, see
|
| 46 |
+
`issue #7649 <https://github.com/sympy/sympy/issues/7649>`_.
|
| 47 |
+
|
| 48 |
+
real
|
| 49 |
+
object can have only values from the set
|
| 50 |
+
of real numbers.
|
| 51 |
+
|
| 52 |
+
extended_real
|
| 53 |
+
object can have only values from the set
|
| 54 |
+
of real numbers, ``oo`` and ``-oo``.
|
| 55 |
+
|
| 56 |
+
integer
|
| 57 |
+
object can have only values from the set
|
| 58 |
+
of integers.
|
| 59 |
+
|
| 60 |
+
odd
|
| 61 |
+
even
|
| 62 |
+
object can have only values from the set of
|
| 63 |
+
odd (even) integers [2]_.
|
| 64 |
+
|
| 65 |
+
prime
|
| 66 |
+
object is a natural number greater than 1 that has
|
| 67 |
+
no positive divisors other than 1 and itself. See [6]_.
|
| 68 |
+
|
| 69 |
+
composite
|
| 70 |
+
object is a positive integer that has at least one positive
|
| 71 |
+
divisor other than 1 or the number itself. See [4]_.
|
| 72 |
+
|
| 73 |
+
zero
|
| 74 |
+
object has the value of 0.
|
| 75 |
+
|
| 76 |
+
nonzero
|
| 77 |
+
object is a real number that is not zero.
|
| 78 |
+
|
| 79 |
+
rational
|
| 80 |
+
object can have only values from the set
|
| 81 |
+
of rationals.
|
| 82 |
+
|
| 83 |
+
algebraic
|
| 84 |
+
object can have only values from the set
|
| 85 |
+
of algebraic numbers [11]_.
|
| 86 |
+
|
| 87 |
+
transcendental
|
| 88 |
+
object can have only values from the set
|
| 89 |
+
of transcendental numbers [10]_.
|
| 90 |
+
|
| 91 |
+
irrational
|
| 92 |
+
object value cannot be represented exactly by :class:`~.Rational`, see [5]_.
|
| 93 |
+
|
| 94 |
+
finite
|
| 95 |
+
infinite
|
| 96 |
+
object absolute value is bounded (arbitrarily large).
|
| 97 |
+
See [7]_, [8]_, [9]_.
|
| 98 |
+
|
| 99 |
+
negative
|
| 100 |
+
nonnegative
|
| 101 |
+
object can have only negative (nonnegative)
|
| 102 |
+
values [1]_.
|
| 103 |
+
|
| 104 |
+
positive
|
| 105 |
+
nonpositive
|
| 106 |
+
object can have only positive (nonpositive) values.
|
| 107 |
+
|
| 108 |
+
extended_negative
|
| 109 |
+
extended_nonnegative
|
| 110 |
+
extended_positive
|
| 111 |
+
extended_nonpositive
|
| 112 |
+
extended_nonzero
|
| 113 |
+
as without the extended part, but also including infinity with
|
| 114 |
+
corresponding sign, e.g., extended_positive includes ``oo``
|
| 115 |
+
|
| 116 |
+
hermitian
|
| 117 |
+
antihermitian
|
| 118 |
+
object belongs to the field of Hermitian
|
| 119 |
+
(antihermitian) operators.
|
| 120 |
+
|
| 121 |
+
Examples
|
| 122 |
+
========
|
| 123 |
+
|
| 124 |
+
>>> from sympy import Symbol
|
| 125 |
+
>>> x = Symbol('x', real=True); x
|
| 126 |
+
x
|
| 127 |
+
>>> x.is_real
|
| 128 |
+
True
|
| 129 |
+
>>> x.is_complex
|
| 130 |
+
True
|
| 131 |
+
|
| 132 |
+
See Also
|
| 133 |
+
========
|
| 134 |
+
|
| 135 |
+
.. seealso::
|
| 136 |
+
|
| 137 |
+
:py:class:`sympy.core.numbers.ImaginaryUnit`
|
| 138 |
+
:py:class:`sympy.core.numbers.Zero`
|
| 139 |
+
:py:class:`sympy.core.numbers.One`
|
| 140 |
+
:py:class:`sympy.core.numbers.Infinity`
|
| 141 |
+
:py:class:`sympy.core.numbers.NegativeInfinity`
|
| 142 |
+
:py:class:`sympy.core.numbers.ComplexInfinity`
|
| 143 |
+
|
| 144 |
+
Notes
|
| 145 |
+
=====
|
| 146 |
+
|
| 147 |
+
The fully-resolved assumptions for any SymPy expression
|
| 148 |
+
can be obtained as follows:
|
| 149 |
+
|
| 150 |
+
>>> from sympy.core.assumptions import assumptions
|
| 151 |
+
>>> x = Symbol('x',positive=True)
|
| 152 |
+
>>> assumptions(x + I)
|
| 153 |
+
{'commutative': True, 'complex': True, 'composite': False, 'even':
|
| 154 |
+
False, 'extended_negative': False, 'extended_nonnegative': False,
|
| 155 |
+
'extended_nonpositive': False, 'extended_nonzero': False,
|
| 156 |
+
'extended_positive': False, 'extended_real': False, 'finite': True,
|
| 157 |
+
'imaginary': False, 'infinite': False, 'integer': False, 'irrational':
|
| 158 |
+
False, 'negative': False, 'noninteger': False, 'nonnegative': False,
|
| 159 |
+
'nonpositive': False, 'nonzero': False, 'odd': False, 'positive':
|
| 160 |
+
False, 'prime': False, 'rational': False, 'real': False, 'zero':
|
| 161 |
+
False}
|
| 162 |
+
|
| 163 |
+
Developers Notes
|
| 164 |
+
================
|
| 165 |
+
|
| 166 |
+
The current (and possibly incomplete) values are stored
|
| 167 |
+
in the ``obj._assumptions dictionary``; queries to getter methods
|
| 168 |
+
(with property decorators) or attributes of objects/classes
|
| 169 |
+
will return values and update the dictionary.
|
| 170 |
+
|
| 171 |
+
>>> eq = x**2 + I
|
| 172 |
+
>>> eq._assumptions
|
| 173 |
+
{}
|
| 174 |
+
>>> eq.is_finite
|
| 175 |
+
True
|
| 176 |
+
>>> eq._assumptions
|
| 177 |
+
{'finite': True, 'infinite': False}
|
| 178 |
+
|
| 179 |
+
For a :class:`~.Symbol`, there are two locations for assumptions that may
|
| 180 |
+
be of interest. The ``assumptions0`` attribute gives the full set of
|
| 181 |
+
assumptions derived from a given set of initial assumptions. The
|
| 182 |
+
latter assumptions are stored as ``Symbol._assumptions_orig``
|
| 183 |
+
|
| 184 |
+
>>> Symbol('x', prime=True, even=True)._assumptions_orig
|
| 185 |
+
{'even': True, 'prime': True}
|
| 186 |
+
|
| 187 |
+
The ``_assumptions_orig`` are not necessarily canonical nor are they filtered
|
| 188 |
+
in any way: they records the assumptions used to instantiate a Symbol and (for
|
| 189 |
+
storage purposes) represent a more compact representation of the assumptions
|
| 190 |
+
needed to recreate the full set in ``Symbol.assumptions0``.
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
References
|
| 194 |
+
==========
|
| 195 |
+
|
| 196 |
+
.. [1] https://en.wikipedia.org/wiki/Negative_number
|
| 197 |
+
.. [2] https://en.wikipedia.org/wiki/Parity_%28mathematics%29
|
| 198 |
+
.. [3] https://en.wikipedia.org/wiki/Imaginary_number
|
| 199 |
+
.. [4] https://en.wikipedia.org/wiki/Composite_number
|
| 200 |
+
.. [5] https://en.wikipedia.org/wiki/Irrational_number
|
| 201 |
+
.. [6] https://en.wikipedia.org/wiki/Prime_number
|
| 202 |
+
.. [7] https://en.wikipedia.org/wiki/Finite
|
| 203 |
+
.. [8] https://docs.python.org/3/library/math.html#math.isfinite
|
| 204 |
+
.. [9] https://numpy.org/doc/stable/reference/generated/numpy.isfinite.html
|
| 205 |
+
.. [10] https://en.wikipedia.org/wiki/Transcendental_number
|
| 206 |
+
.. [11] https://en.wikipedia.org/wiki/Algebraic_number
|
| 207 |
+
.. [12] https://en.wikipedia.org/wiki/Commutative_property
|
| 208 |
+
.. [13] https://en.wikipedia.org/wiki/Complex_number
|
| 209 |
+
|
| 210 |
+
"""
|
| 211 |
+
|
| 212 |
+
from sympy.utilities.exceptions import sympy_deprecation_warning
|
| 213 |
+
|
| 214 |
+
from .facts import FactRules, FactKB
|
| 215 |
+
from .sympify import sympify
|
| 216 |
+
|
| 217 |
+
from sympy.core.random import _assumptions_shuffle as shuffle
|
| 218 |
+
from sympy.core.assumptions_generated import generated_assumptions as _assumptions
|
| 219 |
+
|
| 220 |
+
def _load_pre_generated_assumption_rules() -> FactRules:
|
| 221 |
+
""" Load the assumption rules from pre-generated data
|
| 222 |
+
|
| 223 |
+
To update the pre-generated data, see :method::`_generate_assumption_rules`
|
| 224 |
+
"""
|
| 225 |
+
_assume_rules=FactRules._from_python(_assumptions)
|
| 226 |
+
return _assume_rules
|
| 227 |
+
|
| 228 |
+
def _generate_assumption_rules():
|
| 229 |
+
""" Generate the default assumption rules
|
| 230 |
+
|
| 231 |
+
This method should only be called to update the pre-generated
|
| 232 |
+
assumption rules.
|
| 233 |
+
|
| 234 |
+
To update the pre-generated assumptions run: bin/ask_update.py
|
| 235 |
+
|
| 236 |
+
"""
|
| 237 |
+
_assume_rules = FactRules([
|
| 238 |
+
|
| 239 |
+
'integer -> rational',
|
| 240 |
+
'rational -> real',
|
| 241 |
+
'rational -> algebraic',
|
| 242 |
+
'algebraic -> complex',
|
| 243 |
+
'transcendental == complex & !algebraic',
|
| 244 |
+
'real -> hermitian',
|
| 245 |
+
'imaginary -> complex',
|
| 246 |
+
'imaginary -> antihermitian',
|
| 247 |
+
'extended_real -> commutative',
|
| 248 |
+
'complex -> commutative',
|
| 249 |
+
'complex -> finite',
|
| 250 |
+
|
| 251 |
+
'odd == integer & !even',
|
| 252 |
+
'even == integer & !odd',
|
| 253 |
+
|
| 254 |
+
'real -> complex',
|
| 255 |
+
'extended_real -> real | infinite',
|
| 256 |
+
'real == extended_real & finite',
|
| 257 |
+
|
| 258 |
+
'extended_real == extended_negative | zero | extended_positive',
|
| 259 |
+
'extended_negative == extended_nonpositive & extended_nonzero',
|
| 260 |
+
'extended_positive == extended_nonnegative & extended_nonzero',
|
| 261 |
+
|
| 262 |
+
'extended_nonpositive == extended_real & !extended_positive',
|
| 263 |
+
'extended_nonnegative == extended_real & !extended_negative',
|
| 264 |
+
|
| 265 |
+
'real == negative | zero | positive',
|
| 266 |
+
'negative == nonpositive & nonzero',
|
| 267 |
+
'positive == nonnegative & nonzero',
|
| 268 |
+
|
| 269 |
+
'nonpositive == real & !positive',
|
| 270 |
+
'nonnegative == real & !negative',
|
| 271 |
+
|
| 272 |
+
'positive == extended_positive & finite',
|
| 273 |
+
'negative == extended_negative & finite',
|
| 274 |
+
'nonpositive == extended_nonpositive & finite',
|
| 275 |
+
'nonnegative == extended_nonnegative & finite',
|
| 276 |
+
'nonzero == extended_nonzero & finite',
|
| 277 |
+
|
| 278 |
+
'zero -> even & finite',
|
| 279 |
+
'zero == extended_nonnegative & extended_nonpositive',
|
| 280 |
+
'zero == nonnegative & nonpositive',
|
| 281 |
+
'nonzero -> real',
|
| 282 |
+
|
| 283 |
+
'prime -> integer & positive',
|
| 284 |
+
'composite -> integer & positive & !prime',
|
| 285 |
+
'!composite -> !positive | !even | prime',
|
| 286 |
+
|
| 287 |
+
'irrational == real & !rational',
|
| 288 |
+
|
| 289 |
+
'imaginary -> !extended_real',
|
| 290 |
+
|
| 291 |
+
'infinite == !finite',
|
| 292 |
+
'noninteger == extended_real & !integer',
|
| 293 |
+
'extended_nonzero == extended_real & !zero',
|
| 294 |
+
])
|
| 295 |
+
return _assume_rules
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
_assume_rules = _load_pre_generated_assumption_rules()
|
| 299 |
+
_assume_defined = _assume_rules.defined_facts.copy()
|
| 300 |
+
_assume_defined.add('polar')
|
| 301 |
+
_assume_defined = frozenset(_assume_defined)
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def assumptions(expr, _check=None):
|
| 305 |
+
"""return the T/F assumptions of ``expr``"""
|
| 306 |
+
n = sympify(expr)
|
| 307 |
+
if n.is_Symbol:
|
| 308 |
+
rv = n.assumptions0 # are any important ones missing?
|
| 309 |
+
if _check is not None:
|
| 310 |
+
rv = {k: rv[k] for k in set(rv) & set(_check)}
|
| 311 |
+
return rv
|
| 312 |
+
rv = {}
|
| 313 |
+
for k in _assume_defined if _check is None else _check:
|
| 314 |
+
v = getattr(n, 'is_{}'.format(k))
|
| 315 |
+
if v is not None:
|
| 316 |
+
rv[k] = v
|
| 317 |
+
return rv
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def common_assumptions(exprs, check=None):
|
| 321 |
+
"""return those assumptions which have the same True or False
|
| 322 |
+
value for all the given expressions.
|
| 323 |
+
|
| 324 |
+
Examples
|
| 325 |
+
========
|
| 326 |
+
|
| 327 |
+
>>> from sympy.core import common_assumptions
|
| 328 |
+
>>> from sympy import oo, pi, sqrt
|
| 329 |
+
>>> common_assumptions([-4, 0, sqrt(2), 2, pi, oo])
|
| 330 |
+
{'commutative': True, 'composite': False,
|
| 331 |
+
'extended_real': True, 'imaginary': False, 'odd': False}
|
| 332 |
+
|
| 333 |
+
By default, all assumptions are tested; pass an iterable of the
|
| 334 |
+
assumptions to limit those that are reported:
|
| 335 |
+
|
| 336 |
+
>>> common_assumptions([0, 1, 2], ['positive', 'integer'])
|
| 337 |
+
{'integer': True}
|
| 338 |
+
"""
|
| 339 |
+
check = _assume_defined if check is None else set(check)
|
| 340 |
+
if not check or not exprs:
|
| 341 |
+
return {}
|
| 342 |
+
|
| 343 |
+
# get all assumptions for each
|
| 344 |
+
assume = [assumptions(i, _check=check) for i in sympify(exprs)]
|
| 345 |
+
# focus on those of interest that are True
|
| 346 |
+
for i, e in enumerate(assume):
|
| 347 |
+
assume[i] = {k: e[k] for k in set(e) & check}
|
| 348 |
+
# what assumptions are in common?
|
| 349 |
+
common = set.intersection(*[set(i) for i in assume])
|
| 350 |
+
# which ones hold the same value
|
| 351 |
+
a = assume[0]
|
| 352 |
+
return {k: a[k] for k in common if all(a[k] == b[k]
|
| 353 |
+
for b in assume)}
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
def failing_assumptions(expr, **assumptions):
|
| 357 |
+
"""
|
| 358 |
+
Return a dictionary containing assumptions with values not
|
| 359 |
+
matching those of the passed assumptions.
|
| 360 |
+
|
| 361 |
+
Examples
|
| 362 |
+
========
|
| 363 |
+
|
| 364 |
+
>>> from sympy import failing_assumptions, Symbol
|
| 365 |
+
|
| 366 |
+
>>> x = Symbol('x', positive=True)
|
| 367 |
+
>>> y = Symbol('y')
|
| 368 |
+
>>> failing_assumptions(6*x + y, positive=True)
|
| 369 |
+
{'positive': None}
|
| 370 |
+
|
| 371 |
+
>>> failing_assumptions(x**2 - 1, positive=True)
|
| 372 |
+
{'positive': None}
|
| 373 |
+
|
| 374 |
+
If *expr* satisfies all of the assumptions, an empty dictionary is returned.
|
| 375 |
+
|
| 376 |
+
>>> failing_assumptions(x**2, positive=True)
|
| 377 |
+
{}
|
| 378 |
+
|
| 379 |
+
"""
|
| 380 |
+
expr = sympify(expr)
|
| 381 |
+
failed = {}
|
| 382 |
+
for k in assumptions:
|
| 383 |
+
test = getattr(expr, 'is_%s' % k, None)
|
| 384 |
+
if test is not assumptions[k]:
|
| 385 |
+
failed[k] = test
|
| 386 |
+
return failed # {} or {assumption: value != desired}
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
def check_assumptions(expr, against=None, **assume):
|
| 390 |
+
"""
|
| 391 |
+
Checks whether assumptions of ``expr`` match the T/F assumptions
|
| 392 |
+
given (or possessed by ``against``). True is returned if all
|
| 393 |
+
assumptions match; False is returned if there is a mismatch and
|
| 394 |
+
the assumption in ``expr`` is not None; else None is returned.
|
| 395 |
+
|
| 396 |
+
Explanation
|
| 397 |
+
===========
|
| 398 |
+
|
| 399 |
+
*assume* is a dict of assumptions with True or False values
|
| 400 |
+
|
| 401 |
+
Examples
|
| 402 |
+
========
|
| 403 |
+
|
| 404 |
+
>>> from sympy import Symbol, pi, I, exp, check_assumptions
|
| 405 |
+
>>> check_assumptions(-5, integer=True)
|
| 406 |
+
True
|
| 407 |
+
>>> check_assumptions(pi, real=True, integer=False)
|
| 408 |
+
True
|
| 409 |
+
>>> check_assumptions(pi, negative=True)
|
| 410 |
+
False
|
| 411 |
+
>>> check_assumptions(exp(I*pi/7), real=False)
|
| 412 |
+
True
|
| 413 |
+
>>> x = Symbol('x', positive=True)
|
| 414 |
+
>>> check_assumptions(2*x + 1, positive=True)
|
| 415 |
+
True
|
| 416 |
+
>>> check_assumptions(-2*x - 5, positive=True)
|
| 417 |
+
False
|
| 418 |
+
|
| 419 |
+
To check assumptions of *expr* against another variable or expression,
|
| 420 |
+
pass the expression or variable as ``against``.
|
| 421 |
+
|
| 422 |
+
>>> check_assumptions(2*x + 1, x)
|
| 423 |
+
True
|
| 424 |
+
|
| 425 |
+
To see if a number matches the assumptions of an expression, pass
|
| 426 |
+
the number as the first argument, else its specific assumptions
|
| 427 |
+
may not have a non-None value in the expression:
|
| 428 |
+
|
| 429 |
+
>>> check_assumptions(x, 3)
|
| 430 |
+
>>> check_assumptions(3, x)
|
| 431 |
+
True
|
| 432 |
+
|
| 433 |
+
``None`` is returned if ``check_assumptions()`` could not conclude.
|
| 434 |
+
|
| 435 |
+
>>> check_assumptions(2*x - 1, x)
|
| 436 |
+
|
| 437 |
+
>>> z = Symbol('z')
|
| 438 |
+
>>> check_assumptions(z, real=True)
|
| 439 |
+
|
| 440 |
+
See Also
|
| 441 |
+
========
|
| 442 |
+
|
| 443 |
+
failing_assumptions
|
| 444 |
+
|
| 445 |
+
"""
|
| 446 |
+
expr = sympify(expr)
|
| 447 |
+
if against is not None:
|
| 448 |
+
if assume:
|
| 449 |
+
raise ValueError(
|
| 450 |
+
'Expecting `against` or `assume`, not both.')
|
| 451 |
+
assume = assumptions(against)
|
| 452 |
+
known = True
|
| 453 |
+
for k, v in assume.items():
|
| 454 |
+
if v is None:
|
| 455 |
+
continue
|
| 456 |
+
e = getattr(expr, 'is_' + k, None)
|
| 457 |
+
if e is None:
|
| 458 |
+
known = None
|
| 459 |
+
elif v != e:
|
| 460 |
+
return False
|
| 461 |
+
return known
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
class StdFactKB(FactKB):
|
| 465 |
+
"""A FactKB specialized for the built-in rules
|
| 466 |
+
|
| 467 |
+
This is the only kind of FactKB that Basic objects should use.
|
| 468 |
+
"""
|
| 469 |
+
def __init__(self, facts=None):
|
| 470 |
+
super().__init__(_assume_rules)
|
| 471 |
+
# save a copy of the facts dict
|
| 472 |
+
if not facts:
|
| 473 |
+
self._generator = {}
|
| 474 |
+
elif not isinstance(facts, FactKB):
|
| 475 |
+
self._generator = facts.copy()
|
| 476 |
+
else:
|
| 477 |
+
self._generator = facts.generator
|
| 478 |
+
if facts:
|
| 479 |
+
self.deduce_all_facts(facts)
|
| 480 |
+
|
| 481 |
+
def copy(self):
|
| 482 |
+
return self.__class__(self)
|
| 483 |
+
|
| 484 |
+
@property
|
| 485 |
+
def generator(self):
|
| 486 |
+
return self._generator.copy()
|
| 487 |
+
|
| 488 |
+
|
| 489 |
+
def as_property(fact):
|
| 490 |
+
"""Convert a fact name to the name of the corresponding property"""
|
| 491 |
+
return 'is_%s' % fact
|
| 492 |
+
|
| 493 |
+
|
| 494 |
+
def make_property(fact):
|
| 495 |
+
"""Create the automagic property corresponding to a fact."""
|
| 496 |
+
|
| 497 |
+
def getit(self):
|
| 498 |
+
try:
|
| 499 |
+
return self._assumptions[fact]
|
| 500 |
+
except KeyError:
|
| 501 |
+
if self._assumptions is self.default_assumptions:
|
| 502 |
+
self._assumptions = self.default_assumptions.copy()
|
| 503 |
+
return _ask(fact, self)
|
| 504 |
+
|
| 505 |
+
getit.func_name = as_property(fact)
|
| 506 |
+
return property(getit)
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
def _ask(fact, obj):
|
| 510 |
+
"""
|
| 511 |
+
Find the truth value for a property of an object.
|
| 512 |
+
|
| 513 |
+
This function is called when a request is made to see what a fact
|
| 514 |
+
value is.
|
| 515 |
+
|
| 516 |
+
For this we use several techniques:
|
| 517 |
+
|
| 518 |
+
First, the fact-evaluation function is tried, if it exists (for
|
| 519 |
+
example _eval_is_integer). Then we try related facts. For example
|
| 520 |
+
|
| 521 |
+
rational --> integer
|
| 522 |
+
|
| 523 |
+
another example is joined rule:
|
| 524 |
+
|
| 525 |
+
integer & !odd --> even
|
| 526 |
+
|
| 527 |
+
so in the latter case if we are looking at what 'even' value is,
|
| 528 |
+
'integer' and 'odd' facts will be asked.
|
| 529 |
+
|
| 530 |
+
In all cases, when we settle on some fact value, its implications are
|
| 531 |
+
deduced, and the result is cached in ._assumptions.
|
| 532 |
+
"""
|
| 533 |
+
# FactKB which is dict-like and maps facts to their known values:
|
| 534 |
+
assumptions = obj._assumptions
|
| 535 |
+
|
| 536 |
+
# A dict that maps facts to their handlers:
|
| 537 |
+
handler_map = obj._prop_handler
|
| 538 |
+
|
| 539 |
+
# This is our queue of facts to check:
|
| 540 |
+
facts_to_check = [fact]
|
| 541 |
+
facts_queued = {fact}
|
| 542 |
+
|
| 543 |
+
# Loop over the queue as it extends
|
| 544 |
+
for fact_i in facts_to_check:
|
| 545 |
+
|
| 546 |
+
# If fact_i has already been determined then we don't need to rerun the
|
| 547 |
+
# handler. There is a potential race condition for multithreaded code
|
| 548 |
+
# though because it's possible that fact_i was checked in another
|
| 549 |
+
# thread. The main logic of the loop below would potentially skip
|
| 550 |
+
# checking assumptions[fact] in this case so we check it once after the
|
| 551 |
+
# loop to be sure.
|
| 552 |
+
if fact_i in assumptions:
|
| 553 |
+
continue
|
| 554 |
+
|
| 555 |
+
# Now we call the associated handler for fact_i if it exists.
|
| 556 |
+
fact_i_value = None
|
| 557 |
+
handler_i = handler_map.get(fact_i)
|
| 558 |
+
if handler_i is not None:
|
| 559 |
+
fact_i_value = handler_i(obj)
|
| 560 |
+
|
| 561 |
+
# If we get a new value for fact_i then we should update our knowledge
|
| 562 |
+
# of fact_i as well as any related facts that can be inferred using the
|
| 563 |
+
# inference rules connecting the fact_i and any other fact values that
|
| 564 |
+
# are already known.
|
| 565 |
+
if fact_i_value is not None:
|
| 566 |
+
assumptions.deduce_all_facts(((fact_i, fact_i_value),))
|
| 567 |
+
|
| 568 |
+
# Usually if assumptions[fact] is now not None then that is because of
|
| 569 |
+
# the call to deduce_all_facts above. The handler for fact_i returned
|
| 570 |
+
# True or False and knowing fact_i (which is equal to fact in the first
|
| 571 |
+
# iteration) implies knowing a value for fact. It is also possible
|
| 572 |
+
# though that independent code e.g. called indirectly by the handler or
|
| 573 |
+
# called in another thread in a multithreaded context might have
|
| 574 |
+
# resulted in assumptions[fact] being set. Either way we return it.
|
| 575 |
+
fact_value = assumptions.get(fact)
|
| 576 |
+
if fact_value is not None:
|
| 577 |
+
return fact_value
|
| 578 |
+
|
| 579 |
+
# Extend the queue with other facts that might determine fact_i. Here
|
| 580 |
+
# we randomise the order of the facts that are checked. This should not
|
| 581 |
+
# lead to any non-determinism if all handlers are logically consistent
|
| 582 |
+
# with the inference rules for the facts. Non-deterministic assumptions
|
| 583 |
+
# queries can result from bugs in the handlers that are exposed by this
|
| 584 |
+
# call to shuffle. These are pushed to the back of the queue meaning
|
| 585 |
+
# that the inference graph is traversed in breadth-first order.
|
| 586 |
+
new_facts_to_check = list(_assume_rules.prereq[fact_i] - facts_queued)
|
| 587 |
+
shuffle(new_facts_to_check)
|
| 588 |
+
facts_to_check.extend(new_facts_to_check)
|
| 589 |
+
facts_queued.update(new_facts_to_check)
|
| 590 |
+
|
| 591 |
+
# The above loop should be able to handle everything fine in a
|
| 592 |
+
# single-threaded context but in multithreaded code it is possible that
|
| 593 |
+
# this thread skipped computing a particular fact that was computed in
|
| 594 |
+
# another thread (due to the continue). In that case it is possible that
|
| 595 |
+
# fact was inferred and is now stored in the assumptions dict but it wasn't
|
| 596 |
+
# checked for in the body of the loop. This is an obscure case but to make
|
| 597 |
+
# sure we catch it we check once here at the end of the loop.
|
| 598 |
+
if fact in assumptions:
|
| 599 |
+
return assumptions[fact]
|
| 600 |
+
|
| 601 |
+
# This query can not be answered. It's possible that e.g. another thread
|
| 602 |
+
# has already stored None for fact but assumptions._tell does not mind if
|
| 603 |
+
# we call _tell twice setting the same value. If this raises
|
| 604 |
+
# InconsistentAssumptions then it probably means that another thread
|
| 605 |
+
# attempted to compute this and got a value of True or False rather than
|
| 606 |
+
# None. In that case there must be a bug in at least one of the handlers.
|
| 607 |
+
# If the handlers are all deterministic and are consistent with the
|
| 608 |
+
# inference rules then the same value should be computed for fact in all
|
| 609 |
+
# threads.
|
| 610 |
+
assumptions._tell(fact, None)
|
| 611 |
+
return None
|
| 612 |
+
|
| 613 |
+
|
| 614 |
+
def _prepare_class_assumptions(cls):
|
| 615 |
+
"""Precompute class level assumptions and generate handlers.
|
| 616 |
+
|
| 617 |
+
This is called by Basic.__init_subclass__ each time a Basic subclass is
|
| 618 |
+
defined.
|
| 619 |
+
"""
|
| 620 |
+
|
| 621 |
+
local_defs = {}
|
| 622 |
+
for k in _assume_defined:
|
| 623 |
+
attrname = as_property(k)
|
| 624 |
+
v = cls.__dict__.get(attrname, '')
|
| 625 |
+
if isinstance(v, (bool, int, type(None))):
|
| 626 |
+
if v is not None:
|
| 627 |
+
v = bool(v)
|
| 628 |
+
local_defs[k] = v
|
| 629 |
+
|
| 630 |
+
defs = {}
|
| 631 |
+
for base in reversed(cls.__bases__):
|
| 632 |
+
assumptions = getattr(base, '_explicit_class_assumptions', None)
|
| 633 |
+
if assumptions is not None:
|
| 634 |
+
defs.update(assumptions)
|
| 635 |
+
defs.update(local_defs)
|
| 636 |
+
|
| 637 |
+
cls._explicit_class_assumptions = defs
|
| 638 |
+
cls.default_assumptions = StdFactKB(defs)
|
| 639 |
+
|
| 640 |
+
cls._prop_handler = {}
|
| 641 |
+
for k in _assume_defined:
|
| 642 |
+
eval_is_meth = getattr(cls, '_eval_is_%s' % k, None)
|
| 643 |
+
if eval_is_meth is not None:
|
| 644 |
+
cls._prop_handler[k] = eval_is_meth
|
| 645 |
+
|
| 646 |
+
# Put definite results directly into the class dict, for speed
|
| 647 |
+
for k, v in cls.default_assumptions.items():
|
| 648 |
+
setattr(cls, as_property(k), v)
|
| 649 |
+
|
| 650 |
+
# protection e.g. for Integer.is_even=F <- (Rational.is_integer=F)
|
| 651 |
+
derived_from_bases = set()
|
| 652 |
+
for base in cls.__bases__:
|
| 653 |
+
default_assumptions = getattr(base, 'default_assumptions', None)
|
| 654 |
+
# is an assumption-aware class
|
| 655 |
+
if default_assumptions is not None:
|
| 656 |
+
derived_from_bases.update(default_assumptions)
|
| 657 |
+
|
| 658 |
+
for fact in derived_from_bases - set(cls.default_assumptions):
|
| 659 |
+
pname = as_property(fact)
|
| 660 |
+
if pname not in cls.__dict__:
|
| 661 |
+
setattr(cls, pname, make_property(fact))
|
| 662 |
+
|
| 663 |
+
# Finally, add any missing automagic property (e.g. for Basic)
|
| 664 |
+
for fact in _assume_defined:
|
| 665 |
+
pname = as_property(fact)
|
| 666 |
+
if not hasattr(cls, pname):
|
| 667 |
+
setattr(cls, pname, make_property(fact))
|
| 668 |
+
|
| 669 |
+
|
| 670 |
+
# XXX: ManagedProperties used to be the metaclass for Basic but now Basic does
|
| 671 |
+
# not use a metaclass. We leave this here for backwards compatibility for now
|
| 672 |
+
# in case someone has been using the ManagedProperties class in downstream
|
| 673 |
+
# code. The reason that it might have been used is that when subclassing a
|
| 674 |
+
# class and wanting to use a metaclass the metaclass must be a subclass of the
|
| 675 |
+
# metaclass for the class that is being subclassed. Anyone wanting to subclass
|
| 676 |
+
# Basic and use a metaclass in their subclass would have needed to subclass
|
| 677 |
+
# ManagedProperties. Here ManagedProperties is not the metaclass for Basic any
|
| 678 |
+
# more but it should still be usable as a metaclass for Basic subclasses since
|
| 679 |
+
# it is a subclass of type which is now the metaclass for Basic.
|
| 680 |
+
class ManagedProperties(type):
|
| 681 |
+
def __init__(cls, *args, **kwargs):
|
| 682 |
+
msg = ("The ManagedProperties metaclass. "
|
| 683 |
+
"Basic does not use metaclasses any more")
|
| 684 |
+
sympy_deprecation_warning(msg,
|
| 685 |
+
deprecated_since_version="1.12",
|
| 686 |
+
active_deprecations_target='managedproperties')
|
| 687 |
+
|
| 688 |
+
# Here we still call this function in case someone is using
|
| 689 |
+
# ManagedProperties for something that is not a Basic subclass. For
|
| 690 |
+
# Basic subclasses this function is now called by __init_subclass__ and
|
| 691 |
+
# so this metaclass is not needed any more.
|
| 692 |
+
_prepare_class_assumptions(cls)
|
lib/python3.12/site-packages/sympy/core/assumptions_generated.py
ADDED
|
@@ -0,0 +1,1615 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Do NOT manually edit this file.
|
| 3 |
+
Instead, run ./bin/ask_update.py.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
defined_facts = [
|
| 7 |
+
'algebraic',
|
| 8 |
+
'antihermitian',
|
| 9 |
+
'commutative',
|
| 10 |
+
'complex',
|
| 11 |
+
'composite',
|
| 12 |
+
'even',
|
| 13 |
+
'extended_negative',
|
| 14 |
+
'extended_nonnegative',
|
| 15 |
+
'extended_nonpositive',
|
| 16 |
+
'extended_nonzero',
|
| 17 |
+
'extended_positive',
|
| 18 |
+
'extended_real',
|
| 19 |
+
'finite',
|
| 20 |
+
'hermitian',
|
| 21 |
+
'imaginary',
|
| 22 |
+
'infinite',
|
| 23 |
+
'integer',
|
| 24 |
+
'irrational',
|
| 25 |
+
'negative',
|
| 26 |
+
'noninteger',
|
| 27 |
+
'nonnegative',
|
| 28 |
+
'nonpositive',
|
| 29 |
+
'nonzero',
|
| 30 |
+
'odd',
|
| 31 |
+
'positive',
|
| 32 |
+
'prime',
|
| 33 |
+
'rational',
|
| 34 |
+
'real',
|
| 35 |
+
'transcendental',
|
| 36 |
+
'zero',
|
| 37 |
+
] # defined_facts
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
full_implications = dict( [
|
| 41 |
+
# Implications of algebraic = True:
|
| 42 |
+
(('algebraic', True), set( (
|
| 43 |
+
('commutative', True),
|
| 44 |
+
('complex', True),
|
| 45 |
+
('finite', True),
|
| 46 |
+
('infinite', False),
|
| 47 |
+
('transcendental', False),
|
| 48 |
+
) ),
|
| 49 |
+
),
|
| 50 |
+
# Implications of algebraic = False:
|
| 51 |
+
(('algebraic', False), set( (
|
| 52 |
+
('composite', False),
|
| 53 |
+
('even', False),
|
| 54 |
+
('integer', False),
|
| 55 |
+
('odd', False),
|
| 56 |
+
('prime', False),
|
| 57 |
+
('rational', False),
|
| 58 |
+
('zero', False),
|
| 59 |
+
) ),
|
| 60 |
+
),
|
| 61 |
+
# Implications of antihermitian = True:
|
| 62 |
+
(('antihermitian', True), set( (
|
| 63 |
+
) ),
|
| 64 |
+
),
|
| 65 |
+
# Implications of antihermitian = False:
|
| 66 |
+
(('antihermitian', False), set( (
|
| 67 |
+
('imaginary', False),
|
| 68 |
+
) ),
|
| 69 |
+
),
|
| 70 |
+
# Implications of commutative = True:
|
| 71 |
+
(('commutative', True), set( (
|
| 72 |
+
) ),
|
| 73 |
+
),
|
| 74 |
+
# Implications of commutative = False:
|
| 75 |
+
(('commutative', False), set( (
|
| 76 |
+
('algebraic', False),
|
| 77 |
+
('complex', False),
|
| 78 |
+
('composite', False),
|
| 79 |
+
('even', False),
|
| 80 |
+
('extended_negative', False),
|
| 81 |
+
('extended_nonnegative', False),
|
| 82 |
+
('extended_nonpositive', False),
|
| 83 |
+
('extended_nonzero', False),
|
| 84 |
+
('extended_positive', False),
|
| 85 |
+
('extended_real', False),
|
| 86 |
+
('imaginary', False),
|
| 87 |
+
('integer', False),
|
| 88 |
+
('irrational', False),
|
| 89 |
+
('negative', False),
|
| 90 |
+
('noninteger', False),
|
| 91 |
+
('nonnegative', False),
|
| 92 |
+
('nonpositive', False),
|
| 93 |
+
('nonzero', False),
|
| 94 |
+
('odd', False),
|
| 95 |
+
('positive', False),
|
| 96 |
+
('prime', False),
|
| 97 |
+
('rational', False),
|
| 98 |
+
('real', False),
|
| 99 |
+
('transcendental', False),
|
| 100 |
+
('zero', False),
|
| 101 |
+
) ),
|
| 102 |
+
),
|
| 103 |
+
# Implications of complex = True:
|
| 104 |
+
(('complex', True), set( (
|
| 105 |
+
('commutative', True),
|
| 106 |
+
('finite', True),
|
| 107 |
+
('infinite', False),
|
| 108 |
+
) ),
|
| 109 |
+
),
|
| 110 |
+
# Implications of complex = False:
|
| 111 |
+
(('complex', False), set( (
|
| 112 |
+
('algebraic', False),
|
| 113 |
+
('composite', False),
|
| 114 |
+
('even', False),
|
| 115 |
+
('imaginary', False),
|
| 116 |
+
('integer', False),
|
| 117 |
+
('irrational', False),
|
| 118 |
+
('negative', False),
|
| 119 |
+
('nonnegative', False),
|
| 120 |
+
('nonpositive', False),
|
| 121 |
+
('nonzero', False),
|
| 122 |
+
('odd', False),
|
| 123 |
+
('positive', False),
|
| 124 |
+
('prime', False),
|
| 125 |
+
('rational', False),
|
| 126 |
+
('real', False),
|
| 127 |
+
('transcendental', False),
|
| 128 |
+
('zero', False),
|
| 129 |
+
) ),
|
| 130 |
+
),
|
| 131 |
+
# Implications of composite = True:
|
| 132 |
+
(('composite', True), set( (
|
| 133 |
+
('algebraic', True),
|
| 134 |
+
('commutative', True),
|
| 135 |
+
('complex', True),
|
| 136 |
+
('extended_negative', False),
|
| 137 |
+
('extended_nonnegative', True),
|
| 138 |
+
('extended_nonpositive', False),
|
| 139 |
+
('extended_nonzero', True),
|
| 140 |
+
('extended_positive', True),
|
| 141 |
+
('extended_real', True),
|
| 142 |
+
('finite', True),
|
| 143 |
+
('hermitian', True),
|
| 144 |
+
('imaginary', False),
|
| 145 |
+
('infinite', False),
|
| 146 |
+
('integer', True),
|
| 147 |
+
('irrational', False),
|
| 148 |
+
('negative', False),
|
| 149 |
+
('noninteger', False),
|
| 150 |
+
('nonnegative', True),
|
| 151 |
+
('nonpositive', False),
|
| 152 |
+
('nonzero', True),
|
| 153 |
+
('positive', True),
|
| 154 |
+
('prime', False),
|
| 155 |
+
('rational', True),
|
| 156 |
+
('real', True),
|
| 157 |
+
('transcendental', False),
|
| 158 |
+
('zero', False),
|
| 159 |
+
) ),
|
| 160 |
+
),
|
| 161 |
+
# Implications of composite = False:
|
| 162 |
+
(('composite', False), set( (
|
| 163 |
+
) ),
|
| 164 |
+
),
|
| 165 |
+
# Implications of even = True:
|
| 166 |
+
(('even', True), set( (
|
| 167 |
+
('algebraic', True),
|
| 168 |
+
('commutative', True),
|
| 169 |
+
('complex', True),
|
| 170 |
+
('extended_real', True),
|
| 171 |
+
('finite', True),
|
| 172 |
+
('hermitian', True),
|
| 173 |
+
('imaginary', False),
|
| 174 |
+
('infinite', False),
|
| 175 |
+
('integer', True),
|
| 176 |
+
('irrational', False),
|
| 177 |
+
('noninteger', False),
|
| 178 |
+
('odd', False),
|
| 179 |
+
('rational', True),
|
| 180 |
+
('real', True),
|
| 181 |
+
('transcendental', False),
|
| 182 |
+
) ),
|
| 183 |
+
),
|
| 184 |
+
# Implications of even = False:
|
| 185 |
+
(('even', False), set( (
|
| 186 |
+
('zero', False),
|
| 187 |
+
) ),
|
| 188 |
+
),
|
| 189 |
+
# Implications of extended_negative = True:
|
| 190 |
+
(('extended_negative', True), set( (
|
| 191 |
+
('commutative', True),
|
| 192 |
+
('composite', False),
|
| 193 |
+
('extended_nonnegative', False),
|
| 194 |
+
('extended_nonpositive', True),
|
| 195 |
+
('extended_nonzero', True),
|
| 196 |
+
('extended_positive', False),
|
| 197 |
+
('extended_real', True),
|
| 198 |
+
('imaginary', False),
|
| 199 |
+
('nonnegative', False),
|
| 200 |
+
('positive', False),
|
| 201 |
+
('prime', False),
|
| 202 |
+
('zero', False),
|
| 203 |
+
) ),
|
| 204 |
+
),
|
| 205 |
+
# Implications of extended_negative = False:
|
| 206 |
+
(('extended_negative', False), set( (
|
| 207 |
+
('negative', False),
|
| 208 |
+
) ),
|
| 209 |
+
),
|
| 210 |
+
# Implications of extended_nonnegative = True:
|
| 211 |
+
(('extended_nonnegative', True), set( (
|
| 212 |
+
('commutative', True),
|
| 213 |
+
('extended_negative', False),
|
| 214 |
+
('extended_real', True),
|
| 215 |
+
('imaginary', False),
|
| 216 |
+
('negative', False),
|
| 217 |
+
) ),
|
| 218 |
+
),
|
| 219 |
+
# Implications of extended_nonnegative = False:
|
| 220 |
+
(('extended_nonnegative', False), set( (
|
| 221 |
+
('composite', False),
|
| 222 |
+
('extended_positive', False),
|
| 223 |
+
('nonnegative', False),
|
| 224 |
+
('positive', False),
|
| 225 |
+
('prime', False),
|
| 226 |
+
('zero', False),
|
| 227 |
+
) ),
|
| 228 |
+
),
|
| 229 |
+
# Implications of extended_nonpositive = True:
|
| 230 |
+
(('extended_nonpositive', True), set( (
|
| 231 |
+
('commutative', True),
|
| 232 |
+
('composite', False),
|
| 233 |
+
('extended_positive', False),
|
| 234 |
+
('extended_real', True),
|
| 235 |
+
('imaginary', False),
|
| 236 |
+
('positive', False),
|
| 237 |
+
('prime', False),
|
| 238 |
+
) ),
|
| 239 |
+
),
|
| 240 |
+
# Implications of extended_nonpositive = False:
|
| 241 |
+
(('extended_nonpositive', False), set( (
|
| 242 |
+
('extended_negative', False),
|
| 243 |
+
('negative', False),
|
| 244 |
+
('nonpositive', False),
|
| 245 |
+
('zero', False),
|
| 246 |
+
) ),
|
| 247 |
+
),
|
| 248 |
+
# Implications of extended_nonzero = True:
|
| 249 |
+
(('extended_nonzero', True), set( (
|
| 250 |
+
('commutative', True),
|
| 251 |
+
('extended_real', True),
|
| 252 |
+
('imaginary', False),
|
| 253 |
+
('zero', False),
|
| 254 |
+
) ),
|
| 255 |
+
),
|
| 256 |
+
# Implications of extended_nonzero = False:
|
| 257 |
+
(('extended_nonzero', False), set( (
|
| 258 |
+
('composite', False),
|
| 259 |
+
('extended_negative', False),
|
| 260 |
+
('extended_positive', False),
|
| 261 |
+
('negative', False),
|
| 262 |
+
('nonzero', False),
|
| 263 |
+
('positive', False),
|
| 264 |
+
('prime', False),
|
| 265 |
+
) ),
|
| 266 |
+
),
|
| 267 |
+
# Implications of extended_positive = True:
|
| 268 |
+
(('extended_positive', True), set( (
|
| 269 |
+
('commutative', True),
|
| 270 |
+
('extended_negative', False),
|
| 271 |
+
('extended_nonnegative', True),
|
| 272 |
+
('extended_nonpositive', False),
|
| 273 |
+
('extended_nonzero', True),
|
| 274 |
+
('extended_real', True),
|
| 275 |
+
('imaginary', False),
|
| 276 |
+
('negative', False),
|
| 277 |
+
('nonpositive', False),
|
| 278 |
+
('zero', False),
|
| 279 |
+
) ),
|
| 280 |
+
),
|
| 281 |
+
# Implications of extended_positive = False:
|
| 282 |
+
(('extended_positive', False), set( (
|
| 283 |
+
('composite', False),
|
| 284 |
+
('positive', False),
|
| 285 |
+
('prime', False),
|
| 286 |
+
) ),
|
| 287 |
+
),
|
| 288 |
+
# Implications of extended_real = True:
|
| 289 |
+
(('extended_real', True), set( (
|
| 290 |
+
('commutative', True),
|
| 291 |
+
('imaginary', False),
|
| 292 |
+
) ),
|
| 293 |
+
),
|
| 294 |
+
# Implications of extended_real = False:
|
| 295 |
+
(('extended_real', False), set( (
|
| 296 |
+
('composite', False),
|
| 297 |
+
('even', False),
|
| 298 |
+
('extended_negative', False),
|
| 299 |
+
('extended_nonnegative', False),
|
| 300 |
+
('extended_nonpositive', False),
|
| 301 |
+
('extended_nonzero', False),
|
| 302 |
+
('extended_positive', False),
|
| 303 |
+
('integer', False),
|
| 304 |
+
('irrational', False),
|
| 305 |
+
('negative', False),
|
| 306 |
+
('noninteger', False),
|
| 307 |
+
('nonnegative', False),
|
| 308 |
+
('nonpositive', False),
|
| 309 |
+
('nonzero', False),
|
| 310 |
+
('odd', False),
|
| 311 |
+
('positive', False),
|
| 312 |
+
('prime', False),
|
| 313 |
+
('rational', False),
|
| 314 |
+
('real', False),
|
| 315 |
+
('zero', False),
|
| 316 |
+
) ),
|
| 317 |
+
),
|
| 318 |
+
# Implications of finite = True:
|
| 319 |
+
(('finite', True), set( (
|
| 320 |
+
('infinite', False),
|
| 321 |
+
) ),
|
| 322 |
+
),
|
| 323 |
+
# Implications of finite = False:
|
| 324 |
+
(('finite', False), set( (
|
| 325 |
+
('algebraic', False),
|
| 326 |
+
('complex', False),
|
| 327 |
+
('composite', False),
|
| 328 |
+
('even', False),
|
| 329 |
+
('imaginary', False),
|
| 330 |
+
('infinite', True),
|
| 331 |
+
('integer', False),
|
| 332 |
+
('irrational', False),
|
| 333 |
+
('negative', False),
|
| 334 |
+
('nonnegative', False),
|
| 335 |
+
('nonpositive', False),
|
| 336 |
+
('nonzero', False),
|
| 337 |
+
('odd', False),
|
| 338 |
+
('positive', False),
|
| 339 |
+
('prime', False),
|
| 340 |
+
('rational', False),
|
| 341 |
+
('real', False),
|
| 342 |
+
('transcendental', False),
|
| 343 |
+
('zero', False),
|
| 344 |
+
) ),
|
| 345 |
+
),
|
| 346 |
+
# Implications of hermitian = True:
|
| 347 |
+
(('hermitian', True), set( (
|
| 348 |
+
) ),
|
| 349 |
+
),
|
| 350 |
+
# Implications of hermitian = False:
|
| 351 |
+
(('hermitian', False), set( (
|
| 352 |
+
('composite', False),
|
| 353 |
+
('even', False),
|
| 354 |
+
('integer', False),
|
| 355 |
+
('irrational', False),
|
| 356 |
+
('negative', False),
|
| 357 |
+
('nonnegative', False),
|
| 358 |
+
('nonpositive', False),
|
| 359 |
+
('nonzero', False),
|
| 360 |
+
('odd', False),
|
| 361 |
+
('positive', False),
|
| 362 |
+
('prime', False),
|
| 363 |
+
('rational', False),
|
| 364 |
+
('real', False),
|
| 365 |
+
('zero', False),
|
| 366 |
+
) ),
|
| 367 |
+
),
|
| 368 |
+
# Implications of imaginary = True:
|
| 369 |
+
(('imaginary', True), set( (
|
| 370 |
+
('antihermitian', True),
|
| 371 |
+
('commutative', True),
|
| 372 |
+
('complex', True),
|
| 373 |
+
('composite', False),
|
| 374 |
+
('even', False),
|
| 375 |
+
('extended_negative', False),
|
| 376 |
+
('extended_nonnegative', False),
|
| 377 |
+
('extended_nonpositive', False),
|
| 378 |
+
('extended_nonzero', False),
|
| 379 |
+
('extended_positive', False),
|
| 380 |
+
('extended_real', False),
|
| 381 |
+
('finite', True),
|
| 382 |
+
('infinite', False),
|
| 383 |
+
('integer', False),
|
| 384 |
+
('irrational', False),
|
| 385 |
+
('negative', False),
|
| 386 |
+
('noninteger', False),
|
| 387 |
+
('nonnegative', False),
|
| 388 |
+
('nonpositive', False),
|
| 389 |
+
('nonzero', False),
|
| 390 |
+
('odd', False),
|
| 391 |
+
('positive', False),
|
| 392 |
+
('prime', False),
|
| 393 |
+
('rational', False),
|
| 394 |
+
('real', False),
|
| 395 |
+
('zero', False),
|
| 396 |
+
) ),
|
| 397 |
+
),
|
| 398 |
+
# Implications of imaginary = False:
|
| 399 |
+
(('imaginary', False), set( (
|
| 400 |
+
) ),
|
| 401 |
+
),
|
| 402 |
+
# Implications of infinite = True:
|
| 403 |
+
(('infinite', True), set( (
|
| 404 |
+
('algebraic', False),
|
| 405 |
+
('complex', False),
|
| 406 |
+
('composite', False),
|
| 407 |
+
('even', False),
|
| 408 |
+
('finite', False),
|
| 409 |
+
('imaginary', False),
|
| 410 |
+
('integer', False),
|
| 411 |
+
('irrational', False),
|
| 412 |
+
('negative', False),
|
| 413 |
+
('nonnegative', False),
|
| 414 |
+
('nonpositive', False),
|
| 415 |
+
('nonzero', False),
|
| 416 |
+
('odd', False),
|
| 417 |
+
('positive', False),
|
| 418 |
+
('prime', False),
|
| 419 |
+
('rational', False),
|
| 420 |
+
('real', False),
|
| 421 |
+
('transcendental', False),
|
| 422 |
+
('zero', False),
|
| 423 |
+
) ),
|
| 424 |
+
),
|
| 425 |
+
# Implications of infinite = False:
|
| 426 |
+
(('infinite', False), set( (
|
| 427 |
+
('finite', True),
|
| 428 |
+
) ),
|
| 429 |
+
),
|
| 430 |
+
# Implications of integer = True:
|
| 431 |
+
(('integer', True), set( (
|
| 432 |
+
('algebraic', True),
|
| 433 |
+
('commutative', True),
|
| 434 |
+
('complex', True),
|
| 435 |
+
('extended_real', True),
|
| 436 |
+
('finite', True),
|
| 437 |
+
('hermitian', True),
|
| 438 |
+
('imaginary', False),
|
| 439 |
+
('infinite', False),
|
| 440 |
+
('irrational', False),
|
| 441 |
+
('noninteger', False),
|
| 442 |
+
('rational', True),
|
| 443 |
+
('real', True),
|
| 444 |
+
('transcendental', False),
|
| 445 |
+
) ),
|
| 446 |
+
),
|
| 447 |
+
# Implications of integer = False:
|
| 448 |
+
(('integer', False), set( (
|
| 449 |
+
('composite', False),
|
| 450 |
+
('even', False),
|
| 451 |
+
('odd', False),
|
| 452 |
+
('prime', False),
|
| 453 |
+
('zero', False),
|
| 454 |
+
) ),
|
| 455 |
+
),
|
| 456 |
+
# Implications of irrational = True:
|
| 457 |
+
(('irrational', True), set( (
|
| 458 |
+
('commutative', True),
|
| 459 |
+
('complex', True),
|
| 460 |
+
('composite', False),
|
| 461 |
+
('even', False),
|
| 462 |
+
('extended_nonzero', True),
|
| 463 |
+
('extended_real', True),
|
| 464 |
+
('finite', True),
|
| 465 |
+
('hermitian', True),
|
| 466 |
+
('imaginary', False),
|
| 467 |
+
('infinite', False),
|
| 468 |
+
('integer', False),
|
| 469 |
+
('noninteger', True),
|
| 470 |
+
('nonzero', True),
|
| 471 |
+
('odd', False),
|
| 472 |
+
('prime', False),
|
| 473 |
+
('rational', False),
|
| 474 |
+
('real', True),
|
| 475 |
+
('zero', False),
|
| 476 |
+
) ),
|
| 477 |
+
),
|
| 478 |
+
# Implications of irrational = False:
|
| 479 |
+
(('irrational', False), set( (
|
| 480 |
+
) ),
|
| 481 |
+
),
|
| 482 |
+
# Implications of negative = True:
|
| 483 |
+
(('negative', True), set( (
|
| 484 |
+
('commutative', True),
|
| 485 |
+
('complex', True),
|
| 486 |
+
('composite', False),
|
| 487 |
+
('extended_negative', True),
|
| 488 |
+
('extended_nonnegative', False),
|
| 489 |
+
('extended_nonpositive', True),
|
| 490 |
+
('extended_nonzero', True),
|
| 491 |
+
('extended_positive', False),
|
| 492 |
+
('extended_real', True),
|
| 493 |
+
('finite', True),
|
| 494 |
+
('hermitian', True),
|
| 495 |
+
('imaginary', False),
|
| 496 |
+
('infinite', False),
|
| 497 |
+
('nonnegative', False),
|
| 498 |
+
('nonpositive', True),
|
| 499 |
+
('nonzero', True),
|
| 500 |
+
('positive', False),
|
| 501 |
+
('prime', False),
|
| 502 |
+
('real', True),
|
| 503 |
+
('zero', False),
|
| 504 |
+
) ),
|
| 505 |
+
),
|
| 506 |
+
# Implications of negative = False:
|
| 507 |
+
(('negative', False), set( (
|
| 508 |
+
) ),
|
| 509 |
+
),
|
| 510 |
+
# Implications of noninteger = True:
|
| 511 |
+
(('noninteger', True), set( (
|
| 512 |
+
('commutative', True),
|
| 513 |
+
('composite', False),
|
| 514 |
+
('even', False),
|
| 515 |
+
('extended_nonzero', True),
|
| 516 |
+
('extended_real', True),
|
| 517 |
+
('imaginary', False),
|
| 518 |
+
('integer', False),
|
| 519 |
+
('odd', False),
|
| 520 |
+
('prime', False),
|
| 521 |
+
('zero', False),
|
| 522 |
+
) ),
|
| 523 |
+
),
|
| 524 |
+
# Implications of noninteger = False:
|
| 525 |
+
(('noninteger', False), set( (
|
| 526 |
+
) ),
|
| 527 |
+
),
|
| 528 |
+
# Implications of nonnegative = True:
|
| 529 |
+
(('nonnegative', True), set( (
|
| 530 |
+
('commutative', True),
|
| 531 |
+
('complex', True),
|
| 532 |
+
('extended_negative', False),
|
| 533 |
+
('extended_nonnegative', True),
|
| 534 |
+
('extended_real', True),
|
| 535 |
+
('finite', True),
|
| 536 |
+
('hermitian', True),
|
| 537 |
+
('imaginary', False),
|
| 538 |
+
('infinite', False),
|
| 539 |
+
('negative', False),
|
| 540 |
+
('real', True),
|
| 541 |
+
) ),
|
| 542 |
+
),
|
| 543 |
+
# Implications of nonnegative = False:
|
| 544 |
+
(('nonnegative', False), set( (
|
| 545 |
+
('composite', False),
|
| 546 |
+
('positive', False),
|
| 547 |
+
('prime', False),
|
| 548 |
+
('zero', False),
|
| 549 |
+
) ),
|
| 550 |
+
),
|
| 551 |
+
# Implications of nonpositive = True:
|
| 552 |
+
(('nonpositive', True), set( (
|
| 553 |
+
('commutative', True),
|
| 554 |
+
('complex', True),
|
| 555 |
+
('composite', False),
|
| 556 |
+
('extended_nonpositive', True),
|
| 557 |
+
('extended_positive', False),
|
| 558 |
+
('extended_real', True),
|
| 559 |
+
('finite', True),
|
| 560 |
+
('hermitian', True),
|
| 561 |
+
('imaginary', False),
|
| 562 |
+
('infinite', False),
|
| 563 |
+
('positive', False),
|
| 564 |
+
('prime', False),
|
| 565 |
+
('real', True),
|
| 566 |
+
) ),
|
| 567 |
+
),
|
| 568 |
+
# Implications of nonpositive = False:
|
| 569 |
+
(('nonpositive', False), set( (
|
| 570 |
+
('negative', False),
|
| 571 |
+
('zero', False),
|
| 572 |
+
) ),
|
| 573 |
+
),
|
| 574 |
+
# Implications of nonzero = True:
|
| 575 |
+
(('nonzero', True), set( (
|
| 576 |
+
('commutative', True),
|
| 577 |
+
('complex', True),
|
| 578 |
+
('extended_nonzero', True),
|
| 579 |
+
('extended_real', True),
|
| 580 |
+
('finite', True),
|
| 581 |
+
('hermitian', True),
|
| 582 |
+
('imaginary', False),
|
| 583 |
+
('infinite', False),
|
| 584 |
+
('real', True),
|
| 585 |
+
('zero', False),
|
| 586 |
+
) ),
|
| 587 |
+
),
|
| 588 |
+
# Implications of nonzero = False:
|
| 589 |
+
(('nonzero', False), set( (
|
| 590 |
+
('composite', False),
|
| 591 |
+
('negative', False),
|
| 592 |
+
('positive', False),
|
| 593 |
+
('prime', False),
|
| 594 |
+
) ),
|
| 595 |
+
),
|
| 596 |
+
# Implications of odd = True:
|
| 597 |
+
(('odd', True), set( (
|
| 598 |
+
('algebraic', True),
|
| 599 |
+
('commutative', True),
|
| 600 |
+
('complex', True),
|
| 601 |
+
('even', False),
|
| 602 |
+
('extended_nonzero', True),
|
| 603 |
+
('extended_real', True),
|
| 604 |
+
('finite', True),
|
| 605 |
+
('hermitian', True),
|
| 606 |
+
('imaginary', False),
|
| 607 |
+
('infinite', False),
|
| 608 |
+
('integer', True),
|
| 609 |
+
('irrational', False),
|
| 610 |
+
('noninteger', False),
|
| 611 |
+
('nonzero', True),
|
| 612 |
+
('rational', True),
|
| 613 |
+
('real', True),
|
| 614 |
+
('transcendental', False),
|
| 615 |
+
('zero', False),
|
| 616 |
+
) ),
|
| 617 |
+
),
|
| 618 |
+
# Implications of odd = False:
|
| 619 |
+
(('odd', False), set( (
|
| 620 |
+
) ),
|
| 621 |
+
),
|
| 622 |
+
# Implications of positive = True:
|
| 623 |
+
(('positive', True), set( (
|
| 624 |
+
('commutative', True),
|
| 625 |
+
('complex', True),
|
| 626 |
+
('extended_negative', False),
|
| 627 |
+
('extended_nonnegative', True),
|
| 628 |
+
('extended_nonpositive', False),
|
| 629 |
+
('extended_nonzero', True),
|
| 630 |
+
('extended_positive', True),
|
| 631 |
+
('extended_real', True),
|
| 632 |
+
('finite', True),
|
| 633 |
+
('hermitian', True),
|
| 634 |
+
('imaginary', False),
|
| 635 |
+
('infinite', False),
|
| 636 |
+
('negative', False),
|
| 637 |
+
('nonnegative', True),
|
| 638 |
+
('nonpositive', False),
|
| 639 |
+
('nonzero', True),
|
| 640 |
+
('real', True),
|
| 641 |
+
('zero', False),
|
| 642 |
+
) ),
|
| 643 |
+
),
|
| 644 |
+
# Implications of positive = False:
|
| 645 |
+
(('positive', False), set( (
|
| 646 |
+
('composite', False),
|
| 647 |
+
('prime', False),
|
| 648 |
+
) ),
|
| 649 |
+
),
|
| 650 |
+
# Implications of prime = True:
|
| 651 |
+
(('prime', True), set( (
|
| 652 |
+
('algebraic', True),
|
| 653 |
+
('commutative', True),
|
| 654 |
+
('complex', True),
|
| 655 |
+
('composite', False),
|
| 656 |
+
('extended_negative', False),
|
| 657 |
+
('extended_nonnegative', True),
|
| 658 |
+
('extended_nonpositive', False),
|
| 659 |
+
('extended_nonzero', True),
|
| 660 |
+
('extended_positive', True),
|
| 661 |
+
('extended_real', True),
|
| 662 |
+
('finite', True),
|
| 663 |
+
('hermitian', True),
|
| 664 |
+
('imaginary', False),
|
| 665 |
+
('infinite', False),
|
| 666 |
+
('integer', True),
|
| 667 |
+
('irrational', False),
|
| 668 |
+
('negative', False),
|
| 669 |
+
('noninteger', False),
|
| 670 |
+
('nonnegative', True),
|
| 671 |
+
('nonpositive', False),
|
| 672 |
+
('nonzero', True),
|
| 673 |
+
('positive', True),
|
| 674 |
+
('rational', True),
|
| 675 |
+
('real', True),
|
| 676 |
+
('transcendental', False),
|
| 677 |
+
('zero', False),
|
| 678 |
+
) ),
|
| 679 |
+
),
|
| 680 |
+
# Implications of prime = False:
|
| 681 |
+
(('prime', False), set( (
|
| 682 |
+
) ),
|
| 683 |
+
),
|
| 684 |
+
# Implications of rational = True:
|
| 685 |
+
(('rational', True), set( (
|
| 686 |
+
('algebraic', True),
|
| 687 |
+
('commutative', True),
|
| 688 |
+
('complex', True),
|
| 689 |
+
('extended_real', True),
|
| 690 |
+
('finite', True),
|
| 691 |
+
('hermitian', True),
|
| 692 |
+
('imaginary', False),
|
| 693 |
+
('infinite', False),
|
| 694 |
+
('irrational', False),
|
| 695 |
+
('real', True),
|
| 696 |
+
('transcendental', False),
|
| 697 |
+
) ),
|
| 698 |
+
),
|
| 699 |
+
# Implications of rational = False:
|
| 700 |
+
(('rational', False), set( (
|
| 701 |
+
('composite', False),
|
| 702 |
+
('even', False),
|
| 703 |
+
('integer', False),
|
| 704 |
+
('odd', False),
|
| 705 |
+
('prime', False),
|
| 706 |
+
('zero', False),
|
| 707 |
+
) ),
|
| 708 |
+
),
|
| 709 |
+
# Implications of real = True:
|
| 710 |
+
(('real', True), set( (
|
| 711 |
+
('commutative', True),
|
| 712 |
+
('complex', True),
|
| 713 |
+
('extended_real', True),
|
| 714 |
+
('finite', True),
|
| 715 |
+
('hermitian', True),
|
| 716 |
+
('imaginary', False),
|
| 717 |
+
('infinite', False),
|
| 718 |
+
) ),
|
| 719 |
+
),
|
| 720 |
+
# Implications of real = False:
|
| 721 |
+
(('real', False), set( (
|
| 722 |
+
('composite', False),
|
| 723 |
+
('even', False),
|
| 724 |
+
('integer', False),
|
| 725 |
+
('irrational', False),
|
| 726 |
+
('negative', False),
|
| 727 |
+
('nonnegative', False),
|
| 728 |
+
('nonpositive', False),
|
| 729 |
+
('nonzero', False),
|
| 730 |
+
('odd', False),
|
| 731 |
+
('positive', False),
|
| 732 |
+
('prime', False),
|
| 733 |
+
('rational', False),
|
| 734 |
+
('zero', False),
|
| 735 |
+
) ),
|
| 736 |
+
),
|
| 737 |
+
# Implications of transcendental = True:
|
| 738 |
+
(('transcendental', True), set( (
|
| 739 |
+
('algebraic', False),
|
| 740 |
+
('commutative', True),
|
| 741 |
+
('complex', True),
|
| 742 |
+
('composite', False),
|
| 743 |
+
('even', False),
|
| 744 |
+
('finite', True),
|
| 745 |
+
('infinite', False),
|
| 746 |
+
('integer', False),
|
| 747 |
+
('odd', False),
|
| 748 |
+
('prime', False),
|
| 749 |
+
('rational', False),
|
| 750 |
+
('zero', False),
|
| 751 |
+
) ),
|
| 752 |
+
),
|
| 753 |
+
# Implications of transcendental = False:
|
| 754 |
+
(('transcendental', False), set( (
|
| 755 |
+
) ),
|
| 756 |
+
),
|
| 757 |
+
# Implications of zero = True:
|
| 758 |
+
(('zero', True), set( (
|
| 759 |
+
('algebraic', True),
|
| 760 |
+
('commutative', True),
|
| 761 |
+
('complex', True),
|
| 762 |
+
('composite', False),
|
| 763 |
+
('even', True),
|
| 764 |
+
('extended_negative', False),
|
| 765 |
+
('extended_nonnegative', True),
|
| 766 |
+
('extended_nonpositive', True),
|
| 767 |
+
('extended_nonzero', False),
|
| 768 |
+
('extended_positive', False),
|
| 769 |
+
('extended_real', True),
|
| 770 |
+
('finite', True),
|
| 771 |
+
('hermitian', True),
|
| 772 |
+
('imaginary', False),
|
| 773 |
+
('infinite', False),
|
| 774 |
+
('integer', True),
|
| 775 |
+
('irrational', False),
|
| 776 |
+
('negative', False),
|
| 777 |
+
('noninteger', False),
|
| 778 |
+
('nonnegative', True),
|
| 779 |
+
('nonpositive', True),
|
| 780 |
+
('nonzero', False),
|
| 781 |
+
('odd', False),
|
| 782 |
+
('positive', False),
|
| 783 |
+
('prime', False),
|
| 784 |
+
('rational', True),
|
| 785 |
+
('real', True),
|
| 786 |
+
('transcendental', False),
|
| 787 |
+
) ),
|
| 788 |
+
),
|
| 789 |
+
# Implications of zero = False:
|
| 790 |
+
(('zero', False), set( (
|
| 791 |
+
) ),
|
| 792 |
+
),
|
| 793 |
+
] ) # full_implications
|
| 794 |
+
|
| 795 |
+
|
| 796 |
+
prereq = {
|
| 797 |
+
|
| 798 |
+
# facts that could determine the value of algebraic
|
| 799 |
+
'algebraic': {
|
| 800 |
+
'commutative',
|
| 801 |
+
'complex',
|
| 802 |
+
'composite',
|
| 803 |
+
'even',
|
| 804 |
+
'finite',
|
| 805 |
+
'infinite',
|
| 806 |
+
'integer',
|
| 807 |
+
'odd',
|
| 808 |
+
'prime',
|
| 809 |
+
'rational',
|
| 810 |
+
'transcendental',
|
| 811 |
+
'zero',
|
| 812 |
+
},
|
| 813 |
+
|
| 814 |
+
# facts that could determine the value of antihermitian
|
| 815 |
+
'antihermitian': {
|
| 816 |
+
'imaginary',
|
| 817 |
+
},
|
| 818 |
+
|
| 819 |
+
# facts that could determine the value of commutative
|
| 820 |
+
'commutative': {
|
| 821 |
+
'algebraic',
|
| 822 |
+
'complex',
|
| 823 |
+
'composite',
|
| 824 |
+
'even',
|
| 825 |
+
'extended_negative',
|
| 826 |
+
'extended_nonnegative',
|
| 827 |
+
'extended_nonpositive',
|
| 828 |
+
'extended_nonzero',
|
| 829 |
+
'extended_positive',
|
| 830 |
+
'extended_real',
|
| 831 |
+
'imaginary',
|
| 832 |
+
'integer',
|
| 833 |
+
'irrational',
|
| 834 |
+
'negative',
|
| 835 |
+
'noninteger',
|
| 836 |
+
'nonnegative',
|
| 837 |
+
'nonpositive',
|
| 838 |
+
'nonzero',
|
| 839 |
+
'odd',
|
| 840 |
+
'positive',
|
| 841 |
+
'prime',
|
| 842 |
+
'rational',
|
| 843 |
+
'real',
|
| 844 |
+
'transcendental',
|
| 845 |
+
'zero',
|
| 846 |
+
},
|
| 847 |
+
|
| 848 |
+
# facts that could determine the value of complex
|
| 849 |
+
'complex': {
|
| 850 |
+
'algebraic',
|
| 851 |
+
'commutative',
|
| 852 |
+
'composite',
|
| 853 |
+
'even',
|
| 854 |
+
'finite',
|
| 855 |
+
'imaginary',
|
| 856 |
+
'infinite',
|
| 857 |
+
'integer',
|
| 858 |
+
'irrational',
|
| 859 |
+
'negative',
|
| 860 |
+
'nonnegative',
|
| 861 |
+
'nonpositive',
|
| 862 |
+
'nonzero',
|
| 863 |
+
'odd',
|
| 864 |
+
'positive',
|
| 865 |
+
'prime',
|
| 866 |
+
'rational',
|
| 867 |
+
'real',
|
| 868 |
+
'transcendental',
|
| 869 |
+
'zero',
|
| 870 |
+
},
|
| 871 |
+
|
| 872 |
+
# facts that could determine the value of composite
|
| 873 |
+
'composite': {
|
| 874 |
+
'algebraic',
|
| 875 |
+
'commutative',
|
| 876 |
+
'complex',
|
| 877 |
+
'extended_negative',
|
| 878 |
+
'extended_nonnegative',
|
| 879 |
+
'extended_nonpositive',
|
| 880 |
+
'extended_nonzero',
|
| 881 |
+
'extended_positive',
|
| 882 |
+
'extended_real',
|
| 883 |
+
'finite',
|
| 884 |
+
'hermitian',
|
| 885 |
+
'imaginary',
|
| 886 |
+
'infinite',
|
| 887 |
+
'integer',
|
| 888 |
+
'irrational',
|
| 889 |
+
'negative',
|
| 890 |
+
'noninteger',
|
| 891 |
+
'nonnegative',
|
| 892 |
+
'nonpositive',
|
| 893 |
+
'nonzero',
|
| 894 |
+
'positive',
|
| 895 |
+
'prime',
|
| 896 |
+
'rational',
|
| 897 |
+
'real',
|
| 898 |
+
'transcendental',
|
| 899 |
+
'zero',
|
| 900 |
+
},
|
| 901 |
+
|
| 902 |
+
# facts that could determine the value of even
|
| 903 |
+
'even': {
|
| 904 |
+
'algebraic',
|
| 905 |
+
'commutative',
|
| 906 |
+
'complex',
|
| 907 |
+
'extended_real',
|
| 908 |
+
'finite',
|
| 909 |
+
'hermitian',
|
| 910 |
+
'imaginary',
|
| 911 |
+
'infinite',
|
| 912 |
+
'integer',
|
| 913 |
+
'irrational',
|
| 914 |
+
'noninteger',
|
| 915 |
+
'odd',
|
| 916 |
+
'rational',
|
| 917 |
+
'real',
|
| 918 |
+
'transcendental',
|
| 919 |
+
'zero',
|
| 920 |
+
},
|
| 921 |
+
|
| 922 |
+
# facts that could determine the value of extended_negative
|
| 923 |
+
'extended_negative': {
|
| 924 |
+
'commutative',
|
| 925 |
+
'composite',
|
| 926 |
+
'extended_nonnegative',
|
| 927 |
+
'extended_nonpositive',
|
| 928 |
+
'extended_nonzero',
|
| 929 |
+
'extended_positive',
|
| 930 |
+
'extended_real',
|
| 931 |
+
'imaginary',
|
| 932 |
+
'negative',
|
| 933 |
+
'nonnegative',
|
| 934 |
+
'positive',
|
| 935 |
+
'prime',
|
| 936 |
+
'zero',
|
| 937 |
+
},
|
| 938 |
+
|
| 939 |
+
# facts that could determine the value of extended_nonnegative
|
| 940 |
+
'extended_nonnegative': {
|
| 941 |
+
'commutative',
|
| 942 |
+
'composite',
|
| 943 |
+
'extended_negative',
|
| 944 |
+
'extended_positive',
|
| 945 |
+
'extended_real',
|
| 946 |
+
'imaginary',
|
| 947 |
+
'negative',
|
| 948 |
+
'nonnegative',
|
| 949 |
+
'positive',
|
| 950 |
+
'prime',
|
| 951 |
+
'zero',
|
| 952 |
+
},
|
| 953 |
+
|
| 954 |
+
# facts that could determine the value of extended_nonpositive
|
| 955 |
+
'extended_nonpositive': {
|
| 956 |
+
'commutative',
|
| 957 |
+
'composite',
|
| 958 |
+
'extended_negative',
|
| 959 |
+
'extended_positive',
|
| 960 |
+
'extended_real',
|
| 961 |
+
'imaginary',
|
| 962 |
+
'negative',
|
| 963 |
+
'nonpositive',
|
| 964 |
+
'positive',
|
| 965 |
+
'prime',
|
| 966 |
+
'zero',
|
| 967 |
+
},
|
| 968 |
+
|
| 969 |
+
# facts that could determine the value of extended_nonzero
|
| 970 |
+
'extended_nonzero': {
|
| 971 |
+
'commutative',
|
| 972 |
+
'composite',
|
| 973 |
+
'extended_negative',
|
| 974 |
+
'extended_positive',
|
| 975 |
+
'extended_real',
|
| 976 |
+
'imaginary',
|
| 977 |
+
'irrational',
|
| 978 |
+
'negative',
|
| 979 |
+
'noninteger',
|
| 980 |
+
'nonzero',
|
| 981 |
+
'odd',
|
| 982 |
+
'positive',
|
| 983 |
+
'prime',
|
| 984 |
+
'zero',
|
| 985 |
+
},
|
| 986 |
+
|
| 987 |
+
# facts that could determine the value of extended_positive
|
| 988 |
+
'extended_positive': {
|
| 989 |
+
'commutative',
|
| 990 |
+
'composite',
|
| 991 |
+
'extended_negative',
|
| 992 |
+
'extended_nonnegative',
|
| 993 |
+
'extended_nonpositive',
|
| 994 |
+
'extended_nonzero',
|
| 995 |
+
'extended_real',
|
| 996 |
+
'imaginary',
|
| 997 |
+
'negative',
|
| 998 |
+
'nonpositive',
|
| 999 |
+
'positive',
|
| 1000 |
+
'prime',
|
| 1001 |
+
'zero',
|
| 1002 |
+
},
|
| 1003 |
+
|
| 1004 |
+
# facts that could determine the value of extended_real
|
| 1005 |
+
'extended_real': {
|
| 1006 |
+
'commutative',
|
| 1007 |
+
'composite',
|
| 1008 |
+
'even',
|
| 1009 |
+
'extended_negative',
|
| 1010 |
+
'extended_nonnegative',
|
| 1011 |
+
'extended_nonpositive',
|
| 1012 |
+
'extended_nonzero',
|
| 1013 |
+
'extended_positive',
|
| 1014 |
+
'imaginary',
|
| 1015 |
+
'integer',
|
| 1016 |
+
'irrational',
|
| 1017 |
+
'negative',
|
| 1018 |
+
'noninteger',
|
| 1019 |
+
'nonnegative',
|
| 1020 |
+
'nonpositive',
|
| 1021 |
+
'nonzero',
|
| 1022 |
+
'odd',
|
| 1023 |
+
'positive',
|
| 1024 |
+
'prime',
|
| 1025 |
+
'rational',
|
| 1026 |
+
'real',
|
| 1027 |
+
'zero',
|
| 1028 |
+
},
|
| 1029 |
+
|
| 1030 |
+
# facts that could determine the value of finite
|
| 1031 |
+
'finite': {
|
| 1032 |
+
'algebraic',
|
| 1033 |
+
'complex',
|
| 1034 |
+
'composite',
|
| 1035 |
+
'even',
|
| 1036 |
+
'imaginary',
|
| 1037 |
+
'infinite',
|
| 1038 |
+
'integer',
|
| 1039 |
+
'irrational',
|
| 1040 |
+
'negative',
|
| 1041 |
+
'nonnegative',
|
| 1042 |
+
'nonpositive',
|
| 1043 |
+
'nonzero',
|
| 1044 |
+
'odd',
|
| 1045 |
+
'positive',
|
| 1046 |
+
'prime',
|
| 1047 |
+
'rational',
|
| 1048 |
+
'real',
|
| 1049 |
+
'transcendental',
|
| 1050 |
+
'zero',
|
| 1051 |
+
},
|
| 1052 |
+
|
| 1053 |
+
# facts that could determine the value of hermitian
|
| 1054 |
+
'hermitian': {
|
| 1055 |
+
'composite',
|
| 1056 |
+
'even',
|
| 1057 |
+
'integer',
|
| 1058 |
+
'irrational',
|
| 1059 |
+
'negative',
|
| 1060 |
+
'nonnegative',
|
| 1061 |
+
'nonpositive',
|
| 1062 |
+
'nonzero',
|
| 1063 |
+
'odd',
|
| 1064 |
+
'positive',
|
| 1065 |
+
'prime',
|
| 1066 |
+
'rational',
|
| 1067 |
+
'real',
|
| 1068 |
+
'zero',
|
| 1069 |
+
},
|
| 1070 |
+
|
| 1071 |
+
# facts that could determine the value of imaginary
|
| 1072 |
+
'imaginary': {
|
| 1073 |
+
'antihermitian',
|
| 1074 |
+
'commutative',
|
| 1075 |
+
'complex',
|
| 1076 |
+
'composite',
|
| 1077 |
+
'even',
|
| 1078 |
+
'extended_negative',
|
| 1079 |
+
'extended_nonnegative',
|
| 1080 |
+
'extended_nonpositive',
|
| 1081 |
+
'extended_nonzero',
|
| 1082 |
+
'extended_positive',
|
| 1083 |
+
'extended_real',
|
| 1084 |
+
'finite',
|
| 1085 |
+
'infinite',
|
| 1086 |
+
'integer',
|
| 1087 |
+
'irrational',
|
| 1088 |
+
'negative',
|
| 1089 |
+
'noninteger',
|
| 1090 |
+
'nonnegative',
|
| 1091 |
+
'nonpositive',
|
| 1092 |
+
'nonzero',
|
| 1093 |
+
'odd',
|
| 1094 |
+
'positive',
|
| 1095 |
+
'prime',
|
| 1096 |
+
'rational',
|
| 1097 |
+
'real',
|
| 1098 |
+
'zero',
|
| 1099 |
+
},
|
| 1100 |
+
|
| 1101 |
+
# facts that could determine the value of infinite
|
| 1102 |
+
'infinite': {
|
| 1103 |
+
'algebraic',
|
| 1104 |
+
'complex',
|
| 1105 |
+
'composite',
|
| 1106 |
+
'even',
|
| 1107 |
+
'finite',
|
| 1108 |
+
'imaginary',
|
| 1109 |
+
'integer',
|
| 1110 |
+
'irrational',
|
| 1111 |
+
'negative',
|
| 1112 |
+
'nonnegative',
|
| 1113 |
+
'nonpositive',
|
| 1114 |
+
'nonzero',
|
| 1115 |
+
'odd',
|
| 1116 |
+
'positive',
|
| 1117 |
+
'prime',
|
| 1118 |
+
'rational',
|
| 1119 |
+
'real',
|
| 1120 |
+
'transcendental',
|
| 1121 |
+
'zero',
|
| 1122 |
+
},
|
| 1123 |
+
|
| 1124 |
+
# facts that could determine the value of integer
|
| 1125 |
+
'integer': {
|
| 1126 |
+
'algebraic',
|
| 1127 |
+
'commutative',
|
| 1128 |
+
'complex',
|
| 1129 |
+
'composite',
|
| 1130 |
+
'even',
|
| 1131 |
+
'extended_real',
|
| 1132 |
+
'finite',
|
| 1133 |
+
'hermitian',
|
| 1134 |
+
'imaginary',
|
| 1135 |
+
'infinite',
|
| 1136 |
+
'irrational',
|
| 1137 |
+
'noninteger',
|
| 1138 |
+
'odd',
|
| 1139 |
+
'prime',
|
| 1140 |
+
'rational',
|
| 1141 |
+
'real',
|
| 1142 |
+
'transcendental',
|
| 1143 |
+
'zero',
|
| 1144 |
+
},
|
| 1145 |
+
|
| 1146 |
+
# facts that could determine the value of irrational
|
| 1147 |
+
'irrational': {
|
| 1148 |
+
'commutative',
|
| 1149 |
+
'complex',
|
| 1150 |
+
'composite',
|
| 1151 |
+
'even',
|
| 1152 |
+
'extended_real',
|
| 1153 |
+
'finite',
|
| 1154 |
+
'hermitian',
|
| 1155 |
+
'imaginary',
|
| 1156 |
+
'infinite',
|
| 1157 |
+
'integer',
|
| 1158 |
+
'odd',
|
| 1159 |
+
'prime',
|
| 1160 |
+
'rational',
|
| 1161 |
+
'real',
|
| 1162 |
+
'zero',
|
| 1163 |
+
},
|
| 1164 |
+
|
| 1165 |
+
# facts that could determine the value of negative
|
| 1166 |
+
'negative': {
|
| 1167 |
+
'commutative',
|
| 1168 |
+
'complex',
|
| 1169 |
+
'composite',
|
| 1170 |
+
'extended_negative',
|
| 1171 |
+
'extended_nonnegative',
|
| 1172 |
+
'extended_nonpositive',
|
| 1173 |
+
'extended_nonzero',
|
| 1174 |
+
'extended_positive',
|
| 1175 |
+
'extended_real',
|
| 1176 |
+
'finite',
|
| 1177 |
+
'hermitian',
|
| 1178 |
+
'imaginary',
|
| 1179 |
+
'infinite',
|
| 1180 |
+
'nonnegative',
|
| 1181 |
+
'nonpositive',
|
| 1182 |
+
'nonzero',
|
| 1183 |
+
'positive',
|
| 1184 |
+
'prime',
|
| 1185 |
+
'real',
|
| 1186 |
+
'zero',
|
| 1187 |
+
},
|
| 1188 |
+
|
| 1189 |
+
# facts that could determine the value of noninteger
|
| 1190 |
+
'noninteger': {
|
| 1191 |
+
'commutative',
|
| 1192 |
+
'composite',
|
| 1193 |
+
'even',
|
| 1194 |
+
'extended_real',
|
| 1195 |
+
'imaginary',
|
| 1196 |
+
'integer',
|
| 1197 |
+
'irrational',
|
| 1198 |
+
'odd',
|
| 1199 |
+
'prime',
|
| 1200 |
+
'zero',
|
| 1201 |
+
},
|
| 1202 |
+
|
| 1203 |
+
# facts that could determine the value of nonnegative
|
| 1204 |
+
'nonnegative': {
|
| 1205 |
+
'commutative',
|
| 1206 |
+
'complex',
|
| 1207 |
+
'composite',
|
| 1208 |
+
'extended_negative',
|
| 1209 |
+
'extended_nonnegative',
|
| 1210 |
+
'extended_real',
|
| 1211 |
+
'finite',
|
| 1212 |
+
'hermitian',
|
| 1213 |
+
'imaginary',
|
| 1214 |
+
'infinite',
|
| 1215 |
+
'negative',
|
| 1216 |
+
'positive',
|
| 1217 |
+
'prime',
|
| 1218 |
+
'real',
|
| 1219 |
+
'zero',
|
| 1220 |
+
},
|
| 1221 |
+
|
| 1222 |
+
# facts that could determine the value of nonpositive
|
| 1223 |
+
'nonpositive': {
|
| 1224 |
+
'commutative',
|
| 1225 |
+
'complex',
|
| 1226 |
+
'composite',
|
| 1227 |
+
'extended_nonpositive',
|
| 1228 |
+
'extended_positive',
|
| 1229 |
+
'extended_real',
|
| 1230 |
+
'finite',
|
| 1231 |
+
'hermitian',
|
| 1232 |
+
'imaginary',
|
| 1233 |
+
'infinite',
|
| 1234 |
+
'negative',
|
| 1235 |
+
'positive',
|
| 1236 |
+
'prime',
|
| 1237 |
+
'real',
|
| 1238 |
+
'zero',
|
| 1239 |
+
},
|
| 1240 |
+
|
| 1241 |
+
# facts that could determine the value of nonzero
|
| 1242 |
+
'nonzero': {
|
| 1243 |
+
'commutative',
|
| 1244 |
+
'complex',
|
| 1245 |
+
'composite',
|
| 1246 |
+
'extended_nonzero',
|
| 1247 |
+
'extended_real',
|
| 1248 |
+
'finite',
|
| 1249 |
+
'hermitian',
|
| 1250 |
+
'imaginary',
|
| 1251 |
+
'infinite',
|
| 1252 |
+
'irrational',
|
| 1253 |
+
'negative',
|
| 1254 |
+
'odd',
|
| 1255 |
+
'positive',
|
| 1256 |
+
'prime',
|
| 1257 |
+
'real',
|
| 1258 |
+
'zero',
|
| 1259 |
+
},
|
| 1260 |
+
|
| 1261 |
+
# facts that could determine the value of odd
|
| 1262 |
+
'odd': {
|
| 1263 |
+
'algebraic',
|
| 1264 |
+
'commutative',
|
| 1265 |
+
'complex',
|
| 1266 |
+
'even',
|
| 1267 |
+
'extended_real',
|
| 1268 |
+
'finite',
|
| 1269 |
+
'hermitian',
|
| 1270 |
+
'imaginary',
|
| 1271 |
+
'infinite',
|
| 1272 |
+
'integer',
|
| 1273 |
+
'irrational',
|
| 1274 |
+
'noninteger',
|
| 1275 |
+
'rational',
|
| 1276 |
+
'real',
|
| 1277 |
+
'transcendental',
|
| 1278 |
+
'zero',
|
| 1279 |
+
},
|
| 1280 |
+
|
| 1281 |
+
# facts that could determine the value of positive
|
| 1282 |
+
'positive': {
|
| 1283 |
+
'commutative',
|
| 1284 |
+
'complex',
|
| 1285 |
+
'composite',
|
| 1286 |
+
'extended_negative',
|
| 1287 |
+
'extended_nonnegative',
|
| 1288 |
+
'extended_nonpositive',
|
| 1289 |
+
'extended_nonzero',
|
| 1290 |
+
'extended_positive',
|
| 1291 |
+
'extended_real',
|
| 1292 |
+
'finite',
|
| 1293 |
+
'hermitian',
|
| 1294 |
+
'imaginary',
|
| 1295 |
+
'infinite',
|
| 1296 |
+
'negative',
|
| 1297 |
+
'nonnegative',
|
| 1298 |
+
'nonpositive',
|
| 1299 |
+
'nonzero',
|
| 1300 |
+
'prime',
|
| 1301 |
+
'real',
|
| 1302 |
+
'zero',
|
| 1303 |
+
},
|
| 1304 |
+
|
| 1305 |
+
# facts that could determine the value of prime
|
| 1306 |
+
'prime': {
|
| 1307 |
+
'algebraic',
|
| 1308 |
+
'commutative',
|
| 1309 |
+
'complex',
|
| 1310 |
+
'composite',
|
| 1311 |
+
'extended_negative',
|
| 1312 |
+
'extended_nonnegative',
|
| 1313 |
+
'extended_nonpositive',
|
| 1314 |
+
'extended_nonzero',
|
| 1315 |
+
'extended_positive',
|
| 1316 |
+
'extended_real',
|
| 1317 |
+
'finite',
|
| 1318 |
+
'hermitian',
|
| 1319 |
+
'imaginary',
|
| 1320 |
+
'infinite',
|
| 1321 |
+
'integer',
|
| 1322 |
+
'irrational',
|
| 1323 |
+
'negative',
|
| 1324 |
+
'noninteger',
|
| 1325 |
+
'nonnegative',
|
| 1326 |
+
'nonpositive',
|
| 1327 |
+
'nonzero',
|
| 1328 |
+
'positive',
|
| 1329 |
+
'rational',
|
| 1330 |
+
'real',
|
| 1331 |
+
'transcendental',
|
| 1332 |
+
'zero',
|
| 1333 |
+
},
|
| 1334 |
+
|
| 1335 |
+
# facts that could determine the value of rational
|
| 1336 |
+
'rational': {
|
| 1337 |
+
'algebraic',
|
| 1338 |
+
'commutative',
|
| 1339 |
+
'complex',
|
| 1340 |
+
'composite',
|
| 1341 |
+
'even',
|
| 1342 |
+
'extended_real',
|
| 1343 |
+
'finite',
|
| 1344 |
+
'hermitian',
|
| 1345 |
+
'imaginary',
|
| 1346 |
+
'infinite',
|
| 1347 |
+
'integer',
|
| 1348 |
+
'irrational',
|
| 1349 |
+
'odd',
|
| 1350 |
+
'prime',
|
| 1351 |
+
'real',
|
| 1352 |
+
'transcendental',
|
| 1353 |
+
'zero',
|
| 1354 |
+
},
|
| 1355 |
+
|
| 1356 |
+
# facts that could determine the value of real
|
| 1357 |
+
'real': {
|
| 1358 |
+
'commutative',
|
| 1359 |
+
'complex',
|
| 1360 |
+
'composite',
|
| 1361 |
+
'even',
|
| 1362 |
+
'extended_real',
|
| 1363 |
+
'finite',
|
| 1364 |
+
'hermitian',
|
| 1365 |
+
'imaginary',
|
| 1366 |
+
'infinite',
|
| 1367 |
+
'integer',
|
| 1368 |
+
'irrational',
|
| 1369 |
+
'negative',
|
| 1370 |
+
'nonnegative',
|
| 1371 |
+
'nonpositive',
|
| 1372 |
+
'nonzero',
|
| 1373 |
+
'odd',
|
| 1374 |
+
'positive',
|
| 1375 |
+
'prime',
|
| 1376 |
+
'rational',
|
| 1377 |
+
'zero',
|
| 1378 |
+
},
|
| 1379 |
+
|
| 1380 |
+
# facts that could determine the value of transcendental
|
| 1381 |
+
'transcendental': {
|
| 1382 |
+
'algebraic',
|
| 1383 |
+
'commutative',
|
| 1384 |
+
'complex',
|
| 1385 |
+
'composite',
|
| 1386 |
+
'even',
|
| 1387 |
+
'finite',
|
| 1388 |
+
'infinite',
|
| 1389 |
+
'integer',
|
| 1390 |
+
'odd',
|
| 1391 |
+
'prime',
|
| 1392 |
+
'rational',
|
| 1393 |
+
'zero',
|
| 1394 |
+
},
|
| 1395 |
+
|
| 1396 |
+
# facts that could determine the value of zero
|
| 1397 |
+
'zero': {
|
| 1398 |
+
'algebraic',
|
| 1399 |
+
'commutative',
|
| 1400 |
+
'complex',
|
| 1401 |
+
'composite',
|
| 1402 |
+
'even',
|
| 1403 |
+
'extended_negative',
|
| 1404 |
+
'extended_nonnegative',
|
| 1405 |
+
'extended_nonpositive',
|
| 1406 |
+
'extended_nonzero',
|
| 1407 |
+
'extended_positive',
|
| 1408 |
+
'extended_real',
|
| 1409 |
+
'finite',
|
| 1410 |
+
'hermitian',
|
| 1411 |
+
'imaginary',
|
| 1412 |
+
'infinite',
|
| 1413 |
+
'integer',
|
| 1414 |
+
'irrational',
|
| 1415 |
+
'negative',
|
| 1416 |
+
'noninteger',
|
| 1417 |
+
'nonnegative',
|
| 1418 |
+
'nonpositive',
|
| 1419 |
+
'nonzero',
|
| 1420 |
+
'odd',
|
| 1421 |
+
'positive',
|
| 1422 |
+
'prime',
|
| 1423 |
+
'rational',
|
| 1424 |
+
'real',
|
| 1425 |
+
'transcendental',
|
| 1426 |
+
},
|
| 1427 |
+
|
| 1428 |
+
} # prereq
|
| 1429 |
+
|
| 1430 |
+
|
| 1431 |
+
# Note: the order of the beta rules is used in the beta_triggers
|
| 1432 |
+
beta_rules = [
|
| 1433 |
+
|
| 1434 |
+
# Rules implying composite = True
|
| 1435 |
+
({('even', True), ('positive', True), ('prime', False)},
|
| 1436 |
+
('composite', True)),
|
| 1437 |
+
|
| 1438 |
+
# Rules implying even = False
|
| 1439 |
+
({('composite', False), ('positive', True), ('prime', False)},
|
| 1440 |
+
('even', False)),
|
| 1441 |
+
|
| 1442 |
+
# Rules implying even = True
|
| 1443 |
+
({('integer', True), ('odd', False)},
|
| 1444 |
+
('even', True)),
|
| 1445 |
+
|
| 1446 |
+
# Rules implying extended_negative = True
|
| 1447 |
+
({('extended_positive', False), ('extended_real', True), ('zero', False)},
|
| 1448 |
+
('extended_negative', True)),
|
| 1449 |
+
({('extended_nonpositive', True), ('extended_nonzero', True)},
|
| 1450 |
+
('extended_negative', True)),
|
| 1451 |
+
|
| 1452 |
+
# Rules implying extended_nonnegative = True
|
| 1453 |
+
({('extended_negative', False), ('extended_real', True)},
|
| 1454 |
+
('extended_nonnegative', True)),
|
| 1455 |
+
|
| 1456 |
+
# Rules implying extended_nonpositive = True
|
| 1457 |
+
({('extended_positive', False), ('extended_real', True)},
|
| 1458 |
+
('extended_nonpositive', True)),
|
| 1459 |
+
|
| 1460 |
+
# Rules implying extended_nonzero = True
|
| 1461 |
+
({('extended_real', True), ('zero', False)},
|
| 1462 |
+
('extended_nonzero', True)),
|
| 1463 |
+
|
| 1464 |
+
# Rules implying extended_positive = True
|
| 1465 |
+
({('extended_negative', False), ('extended_real', True), ('zero', False)},
|
| 1466 |
+
('extended_positive', True)),
|
| 1467 |
+
({('extended_nonnegative', True), ('extended_nonzero', True)},
|
| 1468 |
+
('extended_positive', True)),
|
| 1469 |
+
|
| 1470 |
+
# Rules implying extended_real = False
|
| 1471 |
+
({('infinite', False), ('real', False)},
|
| 1472 |
+
('extended_real', False)),
|
| 1473 |
+
({('extended_negative', False), ('extended_positive', False), ('zero', False)},
|
| 1474 |
+
('extended_real', False)),
|
| 1475 |
+
|
| 1476 |
+
# Rules implying infinite = True
|
| 1477 |
+
({('extended_real', True), ('real', False)},
|
| 1478 |
+
('infinite', True)),
|
| 1479 |
+
|
| 1480 |
+
# Rules implying irrational = True
|
| 1481 |
+
({('rational', False), ('real', True)},
|
| 1482 |
+
('irrational', True)),
|
| 1483 |
+
|
| 1484 |
+
# Rules implying negative = True
|
| 1485 |
+
({('positive', False), ('real', True), ('zero', False)},
|
| 1486 |
+
('negative', True)),
|
| 1487 |
+
({('nonpositive', True), ('nonzero', True)},
|
| 1488 |
+
('negative', True)),
|
| 1489 |
+
({('extended_negative', True), ('finite', True)},
|
| 1490 |
+
('negative', True)),
|
| 1491 |
+
|
| 1492 |
+
# Rules implying noninteger = True
|
| 1493 |
+
({('extended_real', True), ('integer', False)},
|
| 1494 |
+
('noninteger', True)),
|
| 1495 |
+
|
| 1496 |
+
# Rules implying nonnegative = True
|
| 1497 |
+
({('negative', False), ('real', True)},
|
| 1498 |
+
('nonnegative', True)),
|
| 1499 |
+
({('extended_nonnegative', True), ('finite', True)},
|
| 1500 |
+
('nonnegative', True)),
|
| 1501 |
+
|
| 1502 |
+
# Rules implying nonpositive = True
|
| 1503 |
+
({('positive', False), ('real', True)},
|
| 1504 |
+
('nonpositive', True)),
|
| 1505 |
+
({('extended_nonpositive', True), ('finite', True)},
|
| 1506 |
+
('nonpositive', True)),
|
| 1507 |
+
|
| 1508 |
+
# Rules implying nonzero = True
|
| 1509 |
+
({('extended_nonzero', True), ('finite', True)},
|
| 1510 |
+
('nonzero', True)),
|
| 1511 |
+
|
| 1512 |
+
# Rules implying odd = True
|
| 1513 |
+
({('even', False), ('integer', True)},
|
| 1514 |
+
('odd', True)),
|
| 1515 |
+
|
| 1516 |
+
# Rules implying positive = False
|
| 1517 |
+
({('composite', False), ('even', True), ('prime', False)},
|
| 1518 |
+
('positive', False)),
|
| 1519 |
+
|
| 1520 |
+
# Rules implying positive = True
|
| 1521 |
+
({('negative', False), ('real', True), ('zero', False)},
|
| 1522 |
+
('positive', True)),
|
| 1523 |
+
({('nonnegative', True), ('nonzero', True)},
|
| 1524 |
+
('positive', True)),
|
| 1525 |
+
({('extended_positive', True), ('finite', True)},
|
| 1526 |
+
('positive', True)),
|
| 1527 |
+
|
| 1528 |
+
# Rules implying prime = True
|
| 1529 |
+
({('composite', False), ('even', True), ('positive', True)},
|
| 1530 |
+
('prime', True)),
|
| 1531 |
+
|
| 1532 |
+
# Rules implying real = False
|
| 1533 |
+
({('negative', False), ('positive', False), ('zero', False)},
|
| 1534 |
+
('real', False)),
|
| 1535 |
+
|
| 1536 |
+
# Rules implying real = True
|
| 1537 |
+
({('extended_real', True), ('infinite', False)},
|
| 1538 |
+
('real', True)),
|
| 1539 |
+
({('extended_real', True), ('finite', True)},
|
| 1540 |
+
('real', True)),
|
| 1541 |
+
|
| 1542 |
+
# Rules implying transcendental = True
|
| 1543 |
+
({('algebraic', False), ('complex', True)},
|
| 1544 |
+
('transcendental', True)),
|
| 1545 |
+
|
| 1546 |
+
# Rules implying zero = True
|
| 1547 |
+
({('extended_negative', False), ('extended_positive', False), ('extended_real', True)},
|
| 1548 |
+
('zero', True)),
|
| 1549 |
+
({('negative', False), ('positive', False), ('real', True)},
|
| 1550 |
+
('zero', True)),
|
| 1551 |
+
({('extended_nonnegative', True), ('extended_nonpositive', True)},
|
| 1552 |
+
('zero', True)),
|
| 1553 |
+
({('nonnegative', True), ('nonpositive', True)},
|
| 1554 |
+
('zero', True)),
|
| 1555 |
+
|
| 1556 |
+
] # beta_rules
|
| 1557 |
+
beta_triggers = {
|
| 1558 |
+
('algebraic', False): [32, 11, 3, 8, 29, 14, 25, 13, 17, 7],
|
| 1559 |
+
('algebraic', True): [10, 30, 31, 27, 16, 21, 19, 22],
|
| 1560 |
+
('antihermitian', False): [],
|
| 1561 |
+
('commutative', False): [],
|
| 1562 |
+
('complex', False): [10, 12, 11, 3, 8, 17, 7],
|
| 1563 |
+
('complex', True): [32, 10, 30, 31, 27, 16, 21, 19, 22],
|
| 1564 |
+
('composite', False): [1, 28, 24],
|
| 1565 |
+
('composite', True): [23, 2],
|
| 1566 |
+
('even', False): [23, 11, 3, 8, 29, 14, 25, 7],
|
| 1567 |
+
('even', True): [3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 0, 28, 24, 7],
|
| 1568 |
+
('extended_negative', False): [11, 33, 8, 5, 29, 34, 25, 18],
|
| 1569 |
+
('extended_negative', True): [30, 12, 31, 29, 14, 20, 16, 21, 22, 17],
|
| 1570 |
+
('extended_nonnegative', False): [11, 3, 6, 29, 14, 20, 7],
|
| 1571 |
+
('extended_nonnegative', True): [30, 12, 31, 33, 8, 9, 6, 29, 34, 25, 18, 19, 35, 17, 7],
|
| 1572 |
+
('extended_nonpositive', False): [11, 8, 5, 29, 25, 18, 7],
|
| 1573 |
+
('extended_nonpositive', True): [30, 12, 31, 3, 33, 4, 5, 29, 14, 34, 20, 21, 35, 17, 7],
|
| 1574 |
+
('extended_nonzero', False): [11, 33, 6, 5, 29, 34, 20, 18],
|
| 1575 |
+
('extended_nonzero', True): [30, 12, 31, 3, 8, 4, 9, 6, 5, 29, 14, 25, 22, 17],
|
| 1576 |
+
('extended_positive', False): [11, 3, 33, 6, 29, 14, 34, 20],
|
| 1577 |
+
('extended_positive', True): [30, 12, 31, 29, 25, 18, 27, 19, 22, 17],
|
| 1578 |
+
('extended_real', False): [],
|
| 1579 |
+
('extended_real', True): [30, 12, 31, 3, 33, 8, 6, 5, 17, 7],
|
| 1580 |
+
('finite', False): [11, 3, 8, 17, 7],
|
| 1581 |
+
('finite', True): [10, 30, 31, 27, 16, 21, 19, 22],
|
| 1582 |
+
('hermitian', False): [10, 12, 11, 3, 8, 17, 7],
|
| 1583 |
+
('imaginary', True): [32],
|
| 1584 |
+
('infinite', False): [10, 30, 31, 27, 16, 21, 19, 22],
|
| 1585 |
+
('infinite', True): [11, 3, 8, 17, 7],
|
| 1586 |
+
('integer', False): [11, 3, 8, 29, 14, 25, 17, 7],
|
| 1587 |
+
('integer', True): [23, 2, 3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 7],
|
| 1588 |
+
('irrational', True): [32, 3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19],
|
| 1589 |
+
('negative', False): [29, 34, 25, 18],
|
| 1590 |
+
('negative', True): [32, 13, 17],
|
| 1591 |
+
('noninteger', True): [30, 12, 31, 3, 8, 4, 9, 6, 5, 29, 14, 25, 22],
|
| 1592 |
+
('nonnegative', False): [11, 3, 8, 29, 14, 20, 7],
|
| 1593 |
+
('nonnegative', True): [32, 33, 8, 9, 6, 34, 25, 26, 20, 27, 21, 22, 35, 36, 13, 17, 7],
|
| 1594 |
+
('nonpositive', False): [11, 3, 8, 29, 25, 18, 7],
|
| 1595 |
+
('nonpositive', True): [32, 3, 33, 4, 5, 14, 34, 15, 18, 16, 19, 22, 35, 36, 13, 17, 7],
|
| 1596 |
+
('nonzero', False): [29, 34, 20, 18],
|
| 1597 |
+
('nonzero', True): [32, 3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19, 13, 17],
|
| 1598 |
+
('odd', False): [2],
|
| 1599 |
+
('odd', True): [3, 8, 4, 9, 6, 5, 14, 25, 15, 26, 20, 18, 27, 16, 21, 19],
|
| 1600 |
+
('positive', False): [29, 14, 34, 20],
|
| 1601 |
+
('positive', True): [32, 0, 1, 28, 13, 17],
|
| 1602 |
+
('prime', False): [0, 1, 24],
|
| 1603 |
+
('prime', True): [23, 2],
|
| 1604 |
+
('rational', False): [11, 3, 8, 29, 14, 25, 13, 17, 7],
|
| 1605 |
+
('rational', True): [3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 17, 7],
|
| 1606 |
+
('real', False): [10, 12, 11, 3, 8, 17, 7],
|
| 1607 |
+
('real', True): [32, 3, 33, 8, 6, 5, 14, 34, 25, 20, 18, 27, 16, 21, 19, 22, 13, 17, 7],
|
| 1608 |
+
('transcendental', True): [10, 30, 31, 11, 3, 8, 29, 14, 25, 27, 16, 21, 19, 22, 13, 17, 7],
|
| 1609 |
+
('zero', False): [11, 3, 8, 29, 14, 25, 7],
|
| 1610 |
+
('zero', True): [],
|
| 1611 |
+
} # beta_triggers
|
| 1612 |
+
|
| 1613 |
+
|
| 1614 |
+
generated_assumptions = {'defined_facts': defined_facts, 'full_implications': full_implications,
|
| 1615 |
+
'prereq': prereq, 'beta_rules': beta_rules, 'beta_triggers': beta_triggers}
|
lib/python3.12/site-packages/sympy/core/backend.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
USE_SYMENGINE = os.getenv('USE_SYMENGINE', '0')
|
| 3 |
+
USE_SYMENGINE = USE_SYMENGINE.lower() in ('1', 't', 'true') # type: ignore
|
| 4 |
+
|
| 5 |
+
if USE_SYMENGINE:
|
| 6 |
+
from symengine import (Symbol, Integer, sympify as sympify_symengine, S,
|
| 7 |
+
SympifyError, exp, log, gamma, sqrt, I, E, pi, Matrix,
|
| 8 |
+
sin, cos, tan, cot, csc, sec, asin, acos, atan, acot, acsc, asec,
|
| 9 |
+
sinh, cosh, tanh, coth, asinh, acosh, atanh, acoth,
|
| 10 |
+
lambdify, symarray, diff, zeros, eye, diag, ones,
|
| 11 |
+
expand, Function, symbols, var, Add, Mul, Derivative,
|
| 12 |
+
ImmutableMatrix, MatrixBase, Rational, Basic)
|
| 13 |
+
from symengine.lib.symengine_wrapper import gcd as igcd
|
| 14 |
+
from symengine import AppliedUndef
|
| 15 |
+
|
| 16 |
+
def sympify(a, *, strict=False):
|
| 17 |
+
"""
|
| 18 |
+
Notes
|
| 19 |
+
=====
|
| 20 |
+
|
| 21 |
+
SymEngine's ``sympify`` does not accept keyword arguments and is
|
| 22 |
+
therefore not compatible with SymPy's ``sympify`` with ``strict=True``
|
| 23 |
+
(which ensures that only the types for which an explicit conversion has
|
| 24 |
+
been defined are converted). This wrapper adds an addiotional parameter
|
| 25 |
+
``strict`` (with default ``False``) that will raise a ``SympifyError``
|
| 26 |
+
if ``strict=True`` and the argument passed to the parameter ``a`` is a
|
| 27 |
+
string.
|
| 28 |
+
|
| 29 |
+
See Also
|
| 30 |
+
========
|
| 31 |
+
|
| 32 |
+
sympify: Converts an arbitrary expression to a type that can be used
|
| 33 |
+
inside SymPy.
|
| 34 |
+
|
| 35 |
+
"""
|
| 36 |
+
# The parameter ``a`` is used for this function to keep compatibility
|
| 37 |
+
# with the SymEngine docstring.
|
| 38 |
+
if strict and isinstance(a, str):
|
| 39 |
+
raise SympifyError(a)
|
| 40 |
+
return sympify_symengine(a)
|
| 41 |
+
|
| 42 |
+
# Keep the SymEngine docstring and append the additional "Notes" and "See
|
| 43 |
+
# Also" sections. Replacement of spaces is required to correctly format the
|
| 44 |
+
# indentation of the combined docstring.
|
| 45 |
+
sympify.__doc__ = (
|
| 46 |
+
sympify_symengine.__doc__
|
| 47 |
+
+ sympify.__doc__.replace(' ', ' ') # type: ignore
|
| 48 |
+
)
|
| 49 |
+
else:
|
| 50 |
+
from sympy.core.add import Add
|
| 51 |
+
from sympy.core.basic import Basic
|
| 52 |
+
from sympy.core.function import (diff, Function, AppliedUndef,
|
| 53 |
+
expand, Derivative)
|
| 54 |
+
from sympy.core.mul import Mul
|
| 55 |
+
from sympy.core.intfunc import igcd
|
| 56 |
+
from sympy.core.numbers import pi, I, Integer, Rational, E
|
| 57 |
+
from sympy.core.singleton import S
|
| 58 |
+
from sympy.core.symbol import Symbol, var, symbols
|
| 59 |
+
from sympy.core.sympify import SympifyError, sympify
|
| 60 |
+
from sympy.functions.elementary.exponential import log, exp
|
| 61 |
+
from sympy.functions.elementary.hyperbolic import (coth, sinh,
|
| 62 |
+
acosh, acoth, tanh, asinh, atanh, cosh)
|
| 63 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 64 |
+
from sympy.functions.elementary.trigonometric import (csc,
|
| 65 |
+
asec, cos, atan, sec, acot, asin, tan, sin, cot, acsc, acos)
|
| 66 |
+
from sympy.functions.special.gamma_functions import gamma
|
| 67 |
+
from sympy.matrices.dense import (eye, zeros, diag, Matrix,
|
| 68 |
+
ones, symarray)
|
| 69 |
+
from sympy.matrices.immutable import ImmutableMatrix
|
| 70 |
+
from sympy.matrices.matrixbase import MatrixBase
|
| 71 |
+
from sympy.utilities.lambdify import lambdify
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
#
|
| 75 |
+
# XXX: Handling of immutable and mutable matrices in SymEngine is inconsistent
|
| 76 |
+
# with SymPy's matrix classes in at least SymEngine version 0.7.0. Until that
|
| 77 |
+
# is fixed the function below is needed for consistent behaviour when
|
| 78 |
+
# attempting to simplify a matrix.
|
| 79 |
+
#
|
| 80 |
+
# Expected behaviour of a SymPy mutable/immutable matrix .simplify() method:
|
| 81 |
+
#
|
| 82 |
+
# Matrix.simplify() : works in place, returns None
|
| 83 |
+
# ImmutableMatrix.simplify() : returns a simplified copy
|
| 84 |
+
#
|
| 85 |
+
# In SymEngine both mutable and immutable matrices simplify in place and return
|
| 86 |
+
# None. This is inconsistent with the matrix being "immutable" and also the
|
| 87 |
+
# returned None leads to problems in the mechanics module.
|
| 88 |
+
#
|
| 89 |
+
# The simplify function should not be used because simplify(M) sympifies the
|
| 90 |
+
# matrix M and the SymEngine matrices all sympify to SymPy matrices. If we want
|
| 91 |
+
# to work with SymEngine matrices then we need to use their .simplify() method
|
| 92 |
+
# but that method does not work correctly with immutable matrices.
|
| 93 |
+
#
|
| 94 |
+
# The _simplify_matrix function can be removed when the SymEngine bug is fixed.
|
| 95 |
+
# Since this should be a temporary problem we do not make this function part of
|
| 96 |
+
# the public API.
|
| 97 |
+
#
|
| 98 |
+
# SymEngine issue: https://github.com/symengine/symengine.py/issues/363
|
| 99 |
+
#
|
| 100 |
+
|
| 101 |
+
def _simplify_matrix(M):
|
| 102 |
+
"""Return a simplified copy of the matrix M"""
|
| 103 |
+
if not isinstance(M, (Matrix, ImmutableMatrix)):
|
| 104 |
+
raise TypeError("The matrix M must be an instance of Matrix or ImmutableMatrix")
|
| 105 |
+
Mnew = M.as_mutable() # makes a copy if mutable
|
| 106 |
+
Mnew.simplify()
|
| 107 |
+
if isinstance(M, ImmutableMatrix):
|
| 108 |
+
Mnew = Mnew.as_immutable()
|
| 109 |
+
return Mnew
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
__all__ = [
|
| 113 |
+
'Symbol', 'Integer', 'sympify', 'S', 'SympifyError', 'exp', 'log',
|
| 114 |
+
'gamma', 'sqrt', 'I', 'E', 'pi', 'Matrix', 'sin', 'cos', 'tan', 'cot',
|
| 115 |
+
'csc', 'sec', 'asin', 'acos', 'atan', 'acot', 'acsc', 'asec', 'sinh',
|
| 116 |
+
'cosh', 'tanh', 'coth', 'asinh', 'acosh', 'atanh', 'acoth', 'lambdify',
|
| 117 |
+
'symarray', 'diff', 'zeros', 'eye', 'diag', 'ones', 'expand', 'Function',
|
| 118 |
+
'symbols', 'var', 'Add', 'Mul', 'Derivative', 'ImmutableMatrix',
|
| 119 |
+
'MatrixBase', 'Rational', 'Basic', 'igcd', 'AppliedUndef',
|
| 120 |
+
]
|
lib/python3.12/site-packages/sympy/core/basic.py
ADDED
|
@@ -0,0 +1,2339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Base class for all the objects in SymPy"""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
from collections import defaultdict
|
| 5 |
+
from collections.abc import Mapping
|
| 6 |
+
from itertools import chain, zip_longest
|
| 7 |
+
from functools import cmp_to_key
|
| 8 |
+
|
| 9 |
+
from .assumptions import _prepare_class_assumptions
|
| 10 |
+
from .cache import cacheit
|
| 11 |
+
from .sympify import _sympify, sympify, SympifyError, _external_converter
|
| 12 |
+
from .sorting import ordered
|
| 13 |
+
from .kind import Kind, UndefinedKind
|
| 14 |
+
from ._print_helpers import Printable
|
| 15 |
+
|
| 16 |
+
from sympy.utilities.decorator import deprecated
|
| 17 |
+
from sympy.utilities.exceptions import sympy_deprecation_warning
|
| 18 |
+
from sympy.utilities.iterables import iterable, numbered_symbols
|
| 19 |
+
from sympy.utilities.misc import filldedent, func_name
|
| 20 |
+
|
| 21 |
+
from inspect import getmro
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def as_Basic(expr):
|
| 25 |
+
"""Return expr as a Basic instance using strict sympify
|
| 26 |
+
or raise a TypeError; this is just a wrapper to _sympify,
|
| 27 |
+
raising a TypeError instead of a SympifyError."""
|
| 28 |
+
try:
|
| 29 |
+
return _sympify(expr)
|
| 30 |
+
except SympifyError:
|
| 31 |
+
raise TypeError(
|
| 32 |
+
'Argument must be a Basic object, not `%s`' % func_name(
|
| 33 |
+
expr))
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# Key for sorting commutative args in canonical order
|
| 37 |
+
# by name. This is used for canonical ordering of the
|
| 38 |
+
# args for Add and Mul *if* the names of both classes
|
| 39 |
+
# being compared appear here. Some things in this list
|
| 40 |
+
# are not spelled the same as their name so they do not,
|
| 41 |
+
# in effect, appear here. See Basic.compare.
|
| 42 |
+
ordering_of_classes = [
|
| 43 |
+
# singleton numbers
|
| 44 |
+
'Zero', 'One', 'Half', 'Infinity', 'NaN', 'NegativeOne', 'NegativeInfinity',
|
| 45 |
+
# numbers
|
| 46 |
+
'Integer', 'Rational', 'Float',
|
| 47 |
+
# singleton symbols
|
| 48 |
+
'Exp1', 'Pi', 'ImaginaryUnit',
|
| 49 |
+
# symbols
|
| 50 |
+
'Symbol', 'Wild',
|
| 51 |
+
# arithmetic operations
|
| 52 |
+
'Pow', 'Mul', 'Add',
|
| 53 |
+
# function values
|
| 54 |
+
'Derivative', 'Integral',
|
| 55 |
+
# defined singleton functions
|
| 56 |
+
'Abs', 'Sign', 'Sqrt',
|
| 57 |
+
'Floor', 'Ceiling',
|
| 58 |
+
'Re', 'Im', 'Arg',
|
| 59 |
+
'Conjugate',
|
| 60 |
+
'Exp', 'Log',
|
| 61 |
+
'Sin', 'Cos', 'Tan', 'Cot', 'ASin', 'ACos', 'ATan', 'ACot',
|
| 62 |
+
'Sinh', 'Cosh', 'Tanh', 'Coth', 'ASinh', 'ACosh', 'ATanh', 'ACoth',
|
| 63 |
+
'RisingFactorial', 'FallingFactorial',
|
| 64 |
+
'factorial', 'binomial',
|
| 65 |
+
'Gamma', 'LowerGamma', 'UpperGamma', 'PolyGamma',
|
| 66 |
+
'Erf',
|
| 67 |
+
# special polynomials
|
| 68 |
+
'Chebyshev', 'Chebyshev2',
|
| 69 |
+
# undefined functions
|
| 70 |
+
'Function', 'WildFunction',
|
| 71 |
+
# anonymous functions
|
| 72 |
+
'Lambda',
|
| 73 |
+
# Landau O symbol
|
| 74 |
+
'Order',
|
| 75 |
+
# relational operations
|
| 76 |
+
'Equality', 'Unequality', 'StrictGreaterThan', 'StrictLessThan',
|
| 77 |
+
'GreaterThan', 'LessThan',
|
| 78 |
+
]
|
| 79 |
+
|
| 80 |
+
def _cmp_name(x: type, y: type) -> int:
|
| 81 |
+
"""return -1, 0, 1 if the name of x is before that of y.
|
| 82 |
+
A string comparison is done if either name does not appear
|
| 83 |
+
in `ordering_of_classes`. This is the helper for
|
| 84 |
+
``Basic.compare``
|
| 85 |
+
|
| 86 |
+
Examples
|
| 87 |
+
========
|
| 88 |
+
|
| 89 |
+
>>> from sympy import cos, tan, sin
|
| 90 |
+
>>> from sympy.core import basic
|
| 91 |
+
>>> save = basic.ordering_of_classes
|
| 92 |
+
>>> basic.ordering_of_classes = ()
|
| 93 |
+
>>> basic._cmp_name(cos, tan)
|
| 94 |
+
-1
|
| 95 |
+
>>> basic.ordering_of_classes = ["tan", "sin", "cos"]
|
| 96 |
+
>>> basic._cmp_name(cos, tan)
|
| 97 |
+
1
|
| 98 |
+
>>> basic._cmp_name(sin, cos)
|
| 99 |
+
-1
|
| 100 |
+
>>> basic.ordering_of_classes = save
|
| 101 |
+
|
| 102 |
+
"""
|
| 103 |
+
# If the other object is not a Basic subclass, then we are not equal to it.
|
| 104 |
+
if not issubclass(y, Basic):
|
| 105 |
+
return -1
|
| 106 |
+
|
| 107 |
+
n1 = x.__name__
|
| 108 |
+
n2 = y.__name__
|
| 109 |
+
if n1 == n2:
|
| 110 |
+
return 0
|
| 111 |
+
|
| 112 |
+
UNKNOWN = len(ordering_of_classes) + 1
|
| 113 |
+
try:
|
| 114 |
+
i1 = ordering_of_classes.index(n1)
|
| 115 |
+
except ValueError:
|
| 116 |
+
i1 = UNKNOWN
|
| 117 |
+
try:
|
| 118 |
+
i2 = ordering_of_classes.index(n2)
|
| 119 |
+
except ValueError:
|
| 120 |
+
i2 = UNKNOWN
|
| 121 |
+
if i1 == UNKNOWN and i2 == UNKNOWN:
|
| 122 |
+
return (n1 > n2) - (n1 < n2)
|
| 123 |
+
return (i1 > i2) - (i1 < i2)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class Basic(Printable):
|
| 127 |
+
"""
|
| 128 |
+
Base class for all SymPy objects.
|
| 129 |
+
|
| 130 |
+
Notes and conventions
|
| 131 |
+
=====================
|
| 132 |
+
|
| 133 |
+
1) Always use ``.args``, when accessing parameters of some instance:
|
| 134 |
+
|
| 135 |
+
>>> from sympy import cot
|
| 136 |
+
>>> from sympy.abc import x, y
|
| 137 |
+
|
| 138 |
+
>>> cot(x).args
|
| 139 |
+
(x,)
|
| 140 |
+
|
| 141 |
+
>>> cot(x).args[0]
|
| 142 |
+
x
|
| 143 |
+
|
| 144 |
+
>>> (x*y).args
|
| 145 |
+
(x, y)
|
| 146 |
+
|
| 147 |
+
>>> (x*y).args[1]
|
| 148 |
+
y
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
2) Never use internal methods or variables (the ones prefixed with ``_``):
|
| 152 |
+
|
| 153 |
+
>>> cot(x)._args # do not use this, use cot(x).args instead
|
| 154 |
+
(x,)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
3) By "SymPy object" we mean something that can be returned by
|
| 158 |
+
``sympify``. But not all objects one encounters using SymPy are
|
| 159 |
+
subclasses of Basic. For example, mutable objects are not:
|
| 160 |
+
|
| 161 |
+
>>> from sympy import Basic, Matrix, sympify
|
| 162 |
+
>>> A = Matrix([[1, 2], [3, 4]]).as_mutable()
|
| 163 |
+
>>> isinstance(A, Basic)
|
| 164 |
+
False
|
| 165 |
+
|
| 166 |
+
>>> B = sympify(A)
|
| 167 |
+
>>> isinstance(B, Basic)
|
| 168 |
+
True
|
| 169 |
+
"""
|
| 170 |
+
__slots__ = ('_mhash', # hash value
|
| 171 |
+
'_args', # arguments
|
| 172 |
+
'_assumptions'
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
_args: tuple[Basic, ...]
|
| 176 |
+
_mhash: int | None
|
| 177 |
+
|
| 178 |
+
@property
|
| 179 |
+
def __sympy__(self):
|
| 180 |
+
return True
|
| 181 |
+
|
| 182 |
+
def __init_subclass__(cls):
|
| 183 |
+
# Initialize the default_assumptions FactKB and also any assumptions
|
| 184 |
+
# property methods. This method will only be called for subclasses of
|
| 185 |
+
# Basic but not for Basic itself so we call
|
| 186 |
+
# _prepare_class_assumptions(Basic) below the class definition.
|
| 187 |
+
super().__init_subclass__()
|
| 188 |
+
_prepare_class_assumptions(cls)
|
| 189 |
+
|
| 190 |
+
# To be overridden with True in the appropriate subclasses
|
| 191 |
+
is_number = False
|
| 192 |
+
is_Atom = False
|
| 193 |
+
is_Symbol = False
|
| 194 |
+
is_symbol = False
|
| 195 |
+
is_Indexed = False
|
| 196 |
+
is_Dummy = False
|
| 197 |
+
is_Wild = False
|
| 198 |
+
is_Function = False
|
| 199 |
+
is_Add = False
|
| 200 |
+
is_Mul = False
|
| 201 |
+
is_Pow = False
|
| 202 |
+
is_Number = False
|
| 203 |
+
is_Float = False
|
| 204 |
+
is_Rational = False
|
| 205 |
+
is_Integer = False
|
| 206 |
+
is_NumberSymbol = False
|
| 207 |
+
is_Order = False
|
| 208 |
+
is_Derivative = False
|
| 209 |
+
is_Piecewise = False
|
| 210 |
+
is_Poly = False
|
| 211 |
+
is_AlgebraicNumber = False
|
| 212 |
+
is_Relational = False
|
| 213 |
+
is_Equality = False
|
| 214 |
+
is_Boolean = False
|
| 215 |
+
is_Not = False
|
| 216 |
+
is_Matrix = False
|
| 217 |
+
is_Vector = False
|
| 218 |
+
is_Point = False
|
| 219 |
+
is_MatAdd = False
|
| 220 |
+
is_MatMul = False
|
| 221 |
+
is_real: bool | None
|
| 222 |
+
is_extended_real: bool | None
|
| 223 |
+
is_zero: bool | None
|
| 224 |
+
is_negative: bool | None
|
| 225 |
+
is_commutative: bool | None
|
| 226 |
+
|
| 227 |
+
kind: Kind = UndefinedKind
|
| 228 |
+
|
| 229 |
+
def __new__(cls, *args):
|
| 230 |
+
obj = object.__new__(cls)
|
| 231 |
+
obj._assumptions = cls.default_assumptions
|
| 232 |
+
obj._mhash = None # will be set by __hash__ method.
|
| 233 |
+
|
| 234 |
+
obj._args = args # all items in args must be Basic objects
|
| 235 |
+
return obj
|
| 236 |
+
|
| 237 |
+
def copy(self):
|
| 238 |
+
return self.func(*self.args)
|
| 239 |
+
|
| 240 |
+
def __getnewargs__(self):
|
| 241 |
+
return self.args
|
| 242 |
+
|
| 243 |
+
def __getstate__(self):
|
| 244 |
+
return None
|
| 245 |
+
|
| 246 |
+
def __setstate__(self, state):
|
| 247 |
+
for name, value in state.items():
|
| 248 |
+
setattr(self, name, value)
|
| 249 |
+
|
| 250 |
+
def __reduce_ex__(self, protocol):
|
| 251 |
+
if protocol < 2:
|
| 252 |
+
msg = "Only pickle protocol 2 or higher is supported by SymPy"
|
| 253 |
+
raise NotImplementedError(msg)
|
| 254 |
+
return super().__reduce_ex__(protocol)
|
| 255 |
+
|
| 256 |
+
def __hash__(self) -> int:
|
| 257 |
+
# hash cannot be cached using cache_it because infinite recurrence
|
| 258 |
+
# occurs as hash is needed for setting cache dictionary keys
|
| 259 |
+
h = self._mhash
|
| 260 |
+
if h is None:
|
| 261 |
+
h = hash((type(self).__name__,) + self._hashable_content())
|
| 262 |
+
self._mhash = h
|
| 263 |
+
return h
|
| 264 |
+
|
| 265 |
+
def _hashable_content(self):
|
| 266 |
+
"""Return a tuple of information about self that can be used to
|
| 267 |
+
compute the hash. If a class defines additional attributes,
|
| 268 |
+
like ``name`` in Symbol, then this method should be updated
|
| 269 |
+
accordingly to return such relevant attributes.
|
| 270 |
+
|
| 271 |
+
Defining more than _hashable_content is necessary if __eq__ has
|
| 272 |
+
been defined by a class. See note about this in Basic.__eq__."""
|
| 273 |
+
return self._args
|
| 274 |
+
|
| 275 |
+
@property
|
| 276 |
+
def assumptions0(self):
|
| 277 |
+
"""
|
| 278 |
+
Return object `type` assumptions.
|
| 279 |
+
|
| 280 |
+
For example:
|
| 281 |
+
|
| 282 |
+
Symbol('x', real=True)
|
| 283 |
+
Symbol('x', integer=True)
|
| 284 |
+
|
| 285 |
+
are different objects. In other words, besides Python type (Symbol in
|
| 286 |
+
this case), the initial assumptions are also forming their typeinfo.
|
| 287 |
+
|
| 288 |
+
Examples
|
| 289 |
+
========
|
| 290 |
+
|
| 291 |
+
>>> from sympy import Symbol
|
| 292 |
+
>>> from sympy.abc import x
|
| 293 |
+
>>> x.assumptions0
|
| 294 |
+
{'commutative': True}
|
| 295 |
+
>>> x = Symbol("x", positive=True)
|
| 296 |
+
>>> x.assumptions0
|
| 297 |
+
{'commutative': True, 'complex': True, 'extended_negative': False,
|
| 298 |
+
'extended_nonnegative': True, 'extended_nonpositive': False,
|
| 299 |
+
'extended_nonzero': True, 'extended_positive': True, 'extended_real':
|
| 300 |
+
True, 'finite': True, 'hermitian': True, 'imaginary': False,
|
| 301 |
+
'infinite': False, 'negative': False, 'nonnegative': True,
|
| 302 |
+
'nonpositive': False, 'nonzero': True, 'positive': True, 'real':
|
| 303 |
+
True, 'zero': False}
|
| 304 |
+
"""
|
| 305 |
+
return {}
|
| 306 |
+
|
| 307 |
+
def compare(self, other):
|
| 308 |
+
"""
|
| 309 |
+
Return -1, 0, 1 if the object is less than, equal,
|
| 310 |
+
or greater than other in a canonical sense.
|
| 311 |
+
Non-Basic are always greater than Basic.
|
| 312 |
+
If both names of the classes being compared appear
|
| 313 |
+
in the `ordering_of_classes` then the ordering will
|
| 314 |
+
depend on the appearance of the names there.
|
| 315 |
+
If either does not appear in that list, then the
|
| 316 |
+
comparison is based on the class name.
|
| 317 |
+
If the names are the same then a comparison is made
|
| 318 |
+
on the length of the hashable content.
|
| 319 |
+
Items of the equal-lengthed contents are then
|
| 320 |
+
successively compared using the same rules. If there
|
| 321 |
+
is never a difference then 0 is returned.
|
| 322 |
+
|
| 323 |
+
Examples
|
| 324 |
+
========
|
| 325 |
+
|
| 326 |
+
>>> from sympy.abc import x, y
|
| 327 |
+
>>> x.compare(y)
|
| 328 |
+
-1
|
| 329 |
+
>>> x.compare(x)
|
| 330 |
+
0
|
| 331 |
+
>>> y.compare(x)
|
| 332 |
+
1
|
| 333 |
+
|
| 334 |
+
"""
|
| 335 |
+
# all redefinitions of __cmp__ method should start with the
|
| 336 |
+
# following lines:
|
| 337 |
+
if self is other:
|
| 338 |
+
return 0
|
| 339 |
+
n1 = self.__class__
|
| 340 |
+
n2 = other.__class__
|
| 341 |
+
c = _cmp_name(n1, n2)
|
| 342 |
+
if c:
|
| 343 |
+
return c
|
| 344 |
+
#
|
| 345 |
+
st = self._hashable_content()
|
| 346 |
+
ot = other._hashable_content()
|
| 347 |
+
c = (len(st) > len(ot)) - (len(st) < len(ot))
|
| 348 |
+
if c:
|
| 349 |
+
return c
|
| 350 |
+
for l, r in zip(st, ot):
|
| 351 |
+
l = Basic(*l) if isinstance(l, frozenset) else l
|
| 352 |
+
r = Basic(*r) if isinstance(r, frozenset) else r
|
| 353 |
+
if isinstance(l, Basic):
|
| 354 |
+
c = l.compare(r)
|
| 355 |
+
else:
|
| 356 |
+
c = (l > r) - (l < r)
|
| 357 |
+
if c:
|
| 358 |
+
return c
|
| 359 |
+
return 0
|
| 360 |
+
|
| 361 |
+
@staticmethod
|
| 362 |
+
def _compare_pretty(a, b):
|
| 363 |
+
"""return -1, 0, 1 if a is canonically less, equal or
|
| 364 |
+
greater than b. This is used when 'order=old' is selected
|
| 365 |
+
for printing. This puts Order last, orders Rationals
|
| 366 |
+
according to value, puts terms in order wrt the power of
|
| 367 |
+
the last power appearing in a term. Ties are broken using
|
| 368 |
+
Basic.compare.
|
| 369 |
+
"""
|
| 370 |
+
from sympy.series.order import Order
|
| 371 |
+
if isinstance(a, Order) and not isinstance(b, Order):
|
| 372 |
+
return 1
|
| 373 |
+
if not isinstance(a, Order) and isinstance(b, Order):
|
| 374 |
+
return -1
|
| 375 |
+
|
| 376 |
+
if a.is_Rational and b.is_Rational:
|
| 377 |
+
l = a.p * b.q
|
| 378 |
+
r = b.p * a.q
|
| 379 |
+
return (l > r) - (l < r)
|
| 380 |
+
else:
|
| 381 |
+
from .symbol import Wild
|
| 382 |
+
p1, p2, p3 = Wild("p1"), Wild("p2"), Wild("p3")
|
| 383 |
+
r_a = a.match(p1 * p2**p3)
|
| 384 |
+
if r_a and p3 in r_a:
|
| 385 |
+
a3 = r_a[p3]
|
| 386 |
+
r_b = b.match(p1 * p2**p3)
|
| 387 |
+
if r_b and p3 in r_b:
|
| 388 |
+
b3 = r_b[p3]
|
| 389 |
+
c = Basic.compare(a3, b3)
|
| 390 |
+
if c != 0:
|
| 391 |
+
return c
|
| 392 |
+
|
| 393 |
+
# break ties
|
| 394 |
+
return Basic.compare(a, b)
|
| 395 |
+
|
| 396 |
+
@classmethod
|
| 397 |
+
def fromiter(cls, args, **assumptions):
|
| 398 |
+
"""
|
| 399 |
+
Create a new object from an iterable.
|
| 400 |
+
|
| 401 |
+
This is a convenience function that allows one to create objects from
|
| 402 |
+
any iterable, without having to convert to a list or tuple first.
|
| 403 |
+
|
| 404 |
+
Examples
|
| 405 |
+
========
|
| 406 |
+
|
| 407 |
+
>>> from sympy import Tuple
|
| 408 |
+
>>> Tuple.fromiter(i for i in range(5))
|
| 409 |
+
(0, 1, 2, 3, 4)
|
| 410 |
+
|
| 411 |
+
"""
|
| 412 |
+
return cls(*tuple(args), **assumptions)
|
| 413 |
+
|
| 414 |
+
@classmethod
|
| 415 |
+
def class_key(cls):
|
| 416 |
+
"""Nice order of classes."""
|
| 417 |
+
return 5, 0, cls.__name__
|
| 418 |
+
|
| 419 |
+
@cacheit
|
| 420 |
+
def sort_key(self, order=None):
|
| 421 |
+
"""
|
| 422 |
+
Return a sort key.
|
| 423 |
+
|
| 424 |
+
Examples
|
| 425 |
+
========
|
| 426 |
+
|
| 427 |
+
>>> from sympy import S, I
|
| 428 |
+
|
| 429 |
+
>>> sorted([S(1)/2, I, -I], key=lambda x: x.sort_key())
|
| 430 |
+
[1/2, -I, I]
|
| 431 |
+
|
| 432 |
+
>>> S("[x, 1/x, 1/x**2, x**2, x**(1/2), x**(1/4), x**(3/2)]")
|
| 433 |
+
[x, 1/x, x**(-2), x**2, sqrt(x), x**(1/4), x**(3/2)]
|
| 434 |
+
>>> sorted(_, key=lambda x: x.sort_key())
|
| 435 |
+
[x**(-2), 1/x, x**(1/4), sqrt(x), x, x**(3/2), x**2]
|
| 436 |
+
|
| 437 |
+
"""
|
| 438 |
+
|
| 439 |
+
# XXX: remove this when issue 5169 is fixed
|
| 440 |
+
def inner_key(arg):
|
| 441 |
+
if isinstance(arg, Basic):
|
| 442 |
+
return arg.sort_key(order)
|
| 443 |
+
else:
|
| 444 |
+
return arg
|
| 445 |
+
|
| 446 |
+
args = self._sorted_args
|
| 447 |
+
args = len(args), tuple([inner_key(arg) for arg in args])
|
| 448 |
+
return self.class_key(), args, S.One.sort_key(), S.One
|
| 449 |
+
|
| 450 |
+
def _do_eq_sympify(self, other):
|
| 451 |
+
"""Returns a boolean indicating whether a == b when either a
|
| 452 |
+
or b is not a Basic. This is only done for types that were either
|
| 453 |
+
added to `converter` by a 3rd party or when the object has `_sympy_`
|
| 454 |
+
defined. This essentially reuses the code in `_sympify` that is
|
| 455 |
+
specific for this use case. Non-user defined types that are meant
|
| 456 |
+
to work with SymPy should be handled directly in the __eq__ methods
|
| 457 |
+
of the `Basic` classes it could equate to and not be converted. Note
|
| 458 |
+
that after conversion, `==` is used again since it is not
|
| 459 |
+
necessarily clear whether `self` or `other`'s __eq__ method needs
|
| 460 |
+
to be used."""
|
| 461 |
+
for superclass in type(other).__mro__:
|
| 462 |
+
conv = _external_converter.get(superclass)
|
| 463 |
+
if conv is not None:
|
| 464 |
+
return self == conv(other)
|
| 465 |
+
if hasattr(other, '_sympy_'):
|
| 466 |
+
return self == other._sympy_()
|
| 467 |
+
return NotImplemented
|
| 468 |
+
|
| 469 |
+
def __eq__(self, other):
|
| 470 |
+
"""Return a boolean indicating whether a == b on the basis of
|
| 471 |
+
their symbolic trees.
|
| 472 |
+
|
| 473 |
+
This is the same as a.compare(b) == 0 but faster.
|
| 474 |
+
|
| 475 |
+
Notes
|
| 476 |
+
=====
|
| 477 |
+
|
| 478 |
+
If a class that overrides __eq__() needs to retain the
|
| 479 |
+
implementation of __hash__() from a parent class, the
|
| 480 |
+
interpreter must be told this explicitly by setting
|
| 481 |
+
__hash__ : Callable[[object], int] = <ParentClass>.__hash__.
|
| 482 |
+
Otherwise the inheritance of __hash__() will be blocked,
|
| 483 |
+
just as if __hash__ had been explicitly set to None.
|
| 484 |
+
|
| 485 |
+
References
|
| 486 |
+
==========
|
| 487 |
+
|
| 488 |
+
from https://docs.python.org/dev/reference/datamodel.html#object.__hash__
|
| 489 |
+
"""
|
| 490 |
+
if self is other:
|
| 491 |
+
return True
|
| 492 |
+
|
| 493 |
+
if not isinstance(other, Basic):
|
| 494 |
+
return self._do_eq_sympify(other)
|
| 495 |
+
|
| 496 |
+
# check for pure number expr
|
| 497 |
+
if not (self.is_Number and other.is_Number) and (
|
| 498 |
+
type(self) != type(other)):
|
| 499 |
+
return False
|
| 500 |
+
a, b = self._hashable_content(), other._hashable_content()
|
| 501 |
+
if a != b:
|
| 502 |
+
return False
|
| 503 |
+
# check number *in* an expression
|
| 504 |
+
for a, b in zip(a, b):
|
| 505 |
+
if not isinstance(a, Basic):
|
| 506 |
+
continue
|
| 507 |
+
if a.is_Number and type(a) != type(b):
|
| 508 |
+
return False
|
| 509 |
+
return True
|
| 510 |
+
|
| 511 |
+
def __ne__(self, other):
|
| 512 |
+
"""``a != b`` -> Compare two symbolic trees and see whether they are different
|
| 513 |
+
|
| 514 |
+
this is the same as:
|
| 515 |
+
|
| 516 |
+
``a.compare(b) != 0``
|
| 517 |
+
|
| 518 |
+
but faster
|
| 519 |
+
"""
|
| 520 |
+
return not self == other
|
| 521 |
+
|
| 522 |
+
def dummy_eq(self, other, symbol=None):
|
| 523 |
+
"""
|
| 524 |
+
Compare two expressions and handle dummy symbols.
|
| 525 |
+
|
| 526 |
+
Examples
|
| 527 |
+
========
|
| 528 |
+
|
| 529 |
+
>>> from sympy import Dummy
|
| 530 |
+
>>> from sympy.abc import x, y
|
| 531 |
+
|
| 532 |
+
>>> u = Dummy('u')
|
| 533 |
+
|
| 534 |
+
>>> (u**2 + 1).dummy_eq(x**2 + 1)
|
| 535 |
+
True
|
| 536 |
+
>>> (u**2 + 1) == (x**2 + 1)
|
| 537 |
+
False
|
| 538 |
+
|
| 539 |
+
>>> (u**2 + y).dummy_eq(x**2 + y, x)
|
| 540 |
+
True
|
| 541 |
+
>>> (u**2 + y).dummy_eq(x**2 + y, y)
|
| 542 |
+
False
|
| 543 |
+
|
| 544 |
+
"""
|
| 545 |
+
s = self.as_dummy()
|
| 546 |
+
o = _sympify(other)
|
| 547 |
+
o = o.as_dummy()
|
| 548 |
+
|
| 549 |
+
dummy_symbols = [i for i in s.free_symbols if i.is_Dummy]
|
| 550 |
+
|
| 551 |
+
if len(dummy_symbols) == 1:
|
| 552 |
+
dummy = dummy_symbols.pop()
|
| 553 |
+
else:
|
| 554 |
+
return s == o
|
| 555 |
+
|
| 556 |
+
if symbol is None:
|
| 557 |
+
symbols = o.free_symbols
|
| 558 |
+
|
| 559 |
+
if len(symbols) == 1:
|
| 560 |
+
symbol = symbols.pop()
|
| 561 |
+
else:
|
| 562 |
+
return s == o
|
| 563 |
+
|
| 564 |
+
tmp = dummy.__class__()
|
| 565 |
+
|
| 566 |
+
return s.xreplace({dummy: tmp}) == o.xreplace({symbol: tmp})
|
| 567 |
+
|
| 568 |
+
def atoms(self, *types):
|
| 569 |
+
"""Returns the atoms that form the current object.
|
| 570 |
+
|
| 571 |
+
By default, only objects that are truly atomic and cannot
|
| 572 |
+
be divided into smaller pieces are returned: symbols, numbers,
|
| 573 |
+
and number symbols like I and pi. It is possible to request
|
| 574 |
+
atoms of any type, however, as demonstrated below.
|
| 575 |
+
|
| 576 |
+
Examples
|
| 577 |
+
========
|
| 578 |
+
|
| 579 |
+
>>> from sympy import I, pi, sin
|
| 580 |
+
>>> from sympy.abc import x, y
|
| 581 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms()
|
| 582 |
+
{1, 2, I, pi, x, y}
|
| 583 |
+
|
| 584 |
+
If one or more types are given, the results will contain only
|
| 585 |
+
those types of atoms.
|
| 586 |
+
|
| 587 |
+
>>> from sympy import Number, NumberSymbol, Symbol
|
| 588 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(Symbol)
|
| 589 |
+
{x, y}
|
| 590 |
+
|
| 591 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(Number)
|
| 592 |
+
{1, 2}
|
| 593 |
+
|
| 594 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol)
|
| 595 |
+
{1, 2, pi}
|
| 596 |
+
|
| 597 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol, I)
|
| 598 |
+
{1, 2, I, pi}
|
| 599 |
+
|
| 600 |
+
Note that I (imaginary unit) and zoo (complex infinity) are special
|
| 601 |
+
types of number symbols and are not part of the NumberSymbol class.
|
| 602 |
+
|
| 603 |
+
The type can be given implicitly, too:
|
| 604 |
+
|
| 605 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(x) # x is a Symbol
|
| 606 |
+
{x, y}
|
| 607 |
+
|
| 608 |
+
Be careful to check your assumptions when using the implicit option
|
| 609 |
+
since ``S(1).is_Integer = True`` but ``type(S(1))`` is ``One``, a special type
|
| 610 |
+
of SymPy atom, while ``type(S(2))`` is type ``Integer`` and will find all
|
| 611 |
+
integers in an expression:
|
| 612 |
+
|
| 613 |
+
>>> from sympy import S
|
| 614 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(S(1))
|
| 615 |
+
{1}
|
| 616 |
+
|
| 617 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(S(2))
|
| 618 |
+
{1, 2}
|
| 619 |
+
|
| 620 |
+
Finally, arguments to atoms() can select more than atomic atoms: any
|
| 621 |
+
SymPy type (loaded in core/__init__.py) can be listed as an argument
|
| 622 |
+
and those types of "atoms" as found in scanning the arguments of the
|
| 623 |
+
expression recursively:
|
| 624 |
+
|
| 625 |
+
>>> from sympy import Function, Mul
|
| 626 |
+
>>> from sympy.core.function import AppliedUndef
|
| 627 |
+
>>> f = Function('f')
|
| 628 |
+
>>> (1 + f(x) + 2*sin(y + I*pi)).atoms(Function)
|
| 629 |
+
{f(x), sin(y + I*pi)}
|
| 630 |
+
>>> (1 + f(x) + 2*sin(y + I*pi)).atoms(AppliedUndef)
|
| 631 |
+
{f(x)}
|
| 632 |
+
|
| 633 |
+
>>> (1 + x + 2*sin(y + I*pi)).atoms(Mul)
|
| 634 |
+
{I*pi, 2*sin(y + I*pi)}
|
| 635 |
+
|
| 636 |
+
"""
|
| 637 |
+
if types:
|
| 638 |
+
types = tuple(
|
| 639 |
+
[t if isinstance(t, type) else type(t) for t in types])
|
| 640 |
+
nodes = _preorder_traversal(self)
|
| 641 |
+
if types:
|
| 642 |
+
result = {node for node in nodes if isinstance(node, types)}
|
| 643 |
+
else:
|
| 644 |
+
result = {node for node in nodes if not node.args}
|
| 645 |
+
return result
|
| 646 |
+
|
| 647 |
+
@property
|
| 648 |
+
def free_symbols(self) -> set[Basic]:
|
| 649 |
+
"""Return from the atoms of self those which are free symbols.
|
| 650 |
+
|
| 651 |
+
Not all free symbols are ``Symbol``. Eg: IndexedBase('I')[0].free_symbols
|
| 652 |
+
|
| 653 |
+
For most expressions, all symbols are free symbols. For some classes
|
| 654 |
+
this is not true. e.g. Integrals use Symbols for the dummy variables
|
| 655 |
+
which are bound variables, so Integral has a method to return all
|
| 656 |
+
symbols except those. Derivative keeps track of symbols with respect
|
| 657 |
+
to which it will perform a derivative; those are
|
| 658 |
+
bound variables, too, so it has its own free_symbols method.
|
| 659 |
+
|
| 660 |
+
Any other method that uses bound variables should implement a
|
| 661 |
+
free_symbols method."""
|
| 662 |
+
empty: set[Basic] = set()
|
| 663 |
+
return empty.union(*(a.free_symbols for a in self.args))
|
| 664 |
+
|
| 665 |
+
@property
|
| 666 |
+
def expr_free_symbols(self):
|
| 667 |
+
sympy_deprecation_warning("""
|
| 668 |
+
The expr_free_symbols property is deprecated. Use free_symbols to get
|
| 669 |
+
the free symbols of an expression.
|
| 670 |
+
""",
|
| 671 |
+
deprecated_since_version="1.9",
|
| 672 |
+
active_deprecations_target="deprecated-expr-free-symbols")
|
| 673 |
+
return set()
|
| 674 |
+
|
| 675 |
+
def as_dummy(self):
|
| 676 |
+
"""Return the expression with any objects having structurally
|
| 677 |
+
bound symbols replaced with unique, canonical symbols within
|
| 678 |
+
the object in which they appear and having only the default
|
| 679 |
+
assumption for commutativity being True. When applied to a
|
| 680 |
+
symbol a new symbol having only the same commutativity will be
|
| 681 |
+
returned.
|
| 682 |
+
|
| 683 |
+
Examples
|
| 684 |
+
========
|
| 685 |
+
|
| 686 |
+
>>> from sympy import Integral, Symbol
|
| 687 |
+
>>> from sympy.abc import x
|
| 688 |
+
>>> r = Symbol('r', real=True)
|
| 689 |
+
>>> Integral(r, (r, x)).as_dummy()
|
| 690 |
+
Integral(_0, (_0, x))
|
| 691 |
+
>>> _.variables[0].is_real is None
|
| 692 |
+
True
|
| 693 |
+
>>> r.as_dummy()
|
| 694 |
+
_r
|
| 695 |
+
|
| 696 |
+
Notes
|
| 697 |
+
=====
|
| 698 |
+
|
| 699 |
+
Any object that has structurally bound variables should have
|
| 700 |
+
a property, `bound_symbols` that returns those symbols
|
| 701 |
+
appearing in the object.
|
| 702 |
+
"""
|
| 703 |
+
from .symbol import Dummy, Symbol
|
| 704 |
+
def can(x):
|
| 705 |
+
# mask free that shadow bound
|
| 706 |
+
free = x.free_symbols
|
| 707 |
+
bound = set(x.bound_symbols)
|
| 708 |
+
d = {i: Dummy() for i in bound & free}
|
| 709 |
+
x = x.subs(d)
|
| 710 |
+
# replace bound with canonical names
|
| 711 |
+
x = x.xreplace(x.canonical_variables)
|
| 712 |
+
# return after undoing masking
|
| 713 |
+
return x.xreplace({v: k for k, v in d.items()})
|
| 714 |
+
if not self.has(Symbol):
|
| 715 |
+
return self
|
| 716 |
+
return self.replace(
|
| 717 |
+
lambda x: hasattr(x, 'bound_symbols'),
|
| 718 |
+
can,
|
| 719 |
+
simultaneous=False)
|
| 720 |
+
|
| 721 |
+
@property
|
| 722 |
+
def canonical_variables(self):
|
| 723 |
+
"""Return a dictionary mapping any variable defined in
|
| 724 |
+
``self.bound_symbols`` to Symbols that do not clash
|
| 725 |
+
with any free symbols in the expression.
|
| 726 |
+
|
| 727 |
+
Examples
|
| 728 |
+
========
|
| 729 |
+
|
| 730 |
+
>>> from sympy import Lambda
|
| 731 |
+
>>> from sympy.abc import x
|
| 732 |
+
>>> Lambda(x, 2*x).canonical_variables
|
| 733 |
+
{x: _0}
|
| 734 |
+
"""
|
| 735 |
+
if not hasattr(self, 'bound_symbols'):
|
| 736 |
+
return {}
|
| 737 |
+
dums = numbered_symbols('_')
|
| 738 |
+
reps = {}
|
| 739 |
+
# watch out for free symbol that are not in bound symbols;
|
| 740 |
+
# those that are in bound symbols are about to get changed
|
| 741 |
+
bound = self.bound_symbols
|
| 742 |
+
names = {i.name for i in self.free_symbols - set(bound)}
|
| 743 |
+
for b in bound:
|
| 744 |
+
d = next(dums)
|
| 745 |
+
if b.is_Symbol:
|
| 746 |
+
while d.name in names:
|
| 747 |
+
d = next(dums)
|
| 748 |
+
reps[b] = d
|
| 749 |
+
return reps
|
| 750 |
+
|
| 751 |
+
def rcall(self, *args):
|
| 752 |
+
"""Apply on the argument recursively through the expression tree.
|
| 753 |
+
|
| 754 |
+
This method is used to simulate a common abuse of notation for
|
| 755 |
+
operators. For instance, in SymPy the following will not work:
|
| 756 |
+
|
| 757 |
+
``(x+Lambda(y, 2*y))(z) == x+2*z``,
|
| 758 |
+
|
| 759 |
+
however, you can use:
|
| 760 |
+
|
| 761 |
+
>>> from sympy import Lambda
|
| 762 |
+
>>> from sympy.abc import x, y, z
|
| 763 |
+
>>> (x + Lambda(y, 2*y)).rcall(z)
|
| 764 |
+
x + 2*z
|
| 765 |
+
"""
|
| 766 |
+
return Basic._recursive_call(self, args)
|
| 767 |
+
|
| 768 |
+
@staticmethod
|
| 769 |
+
def _recursive_call(expr_to_call, on_args):
|
| 770 |
+
"""Helper for rcall method."""
|
| 771 |
+
from .symbol import Symbol
|
| 772 |
+
def the_call_method_is_overridden(expr):
|
| 773 |
+
for cls in getmro(type(expr)):
|
| 774 |
+
if '__call__' in cls.__dict__:
|
| 775 |
+
return cls != Basic
|
| 776 |
+
|
| 777 |
+
if callable(expr_to_call) and the_call_method_is_overridden(expr_to_call):
|
| 778 |
+
if isinstance(expr_to_call, Symbol): # XXX When you call a Symbol it is
|
| 779 |
+
return expr_to_call # transformed into an UndefFunction
|
| 780 |
+
else:
|
| 781 |
+
return expr_to_call(*on_args)
|
| 782 |
+
elif expr_to_call.args:
|
| 783 |
+
args = [Basic._recursive_call(
|
| 784 |
+
sub, on_args) for sub in expr_to_call.args]
|
| 785 |
+
return type(expr_to_call)(*args)
|
| 786 |
+
else:
|
| 787 |
+
return expr_to_call
|
| 788 |
+
|
| 789 |
+
def is_hypergeometric(self, k):
|
| 790 |
+
from sympy.simplify.simplify import hypersimp
|
| 791 |
+
from sympy.functions.elementary.piecewise import Piecewise
|
| 792 |
+
if self.has(Piecewise):
|
| 793 |
+
return None
|
| 794 |
+
return hypersimp(self, k) is not None
|
| 795 |
+
|
| 796 |
+
@property
|
| 797 |
+
def is_comparable(self):
|
| 798 |
+
"""Return True if self can be computed to a real number
|
| 799 |
+
(or already is a real number) with precision, else False.
|
| 800 |
+
|
| 801 |
+
Examples
|
| 802 |
+
========
|
| 803 |
+
|
| 804 |
+
>>> from sympy import exp_polar, pi, I
|
| 805 |
+
>>> (I*exp_polar(I*pi/2)).is_comparable
|
| 806 |
+
True
|
| 807 |
+
>>> (I*exp_polar(I*pi*2)).is_comparable
|
| 808 |
+
False
|
| 809 |
+
|
| 810 |
+
A False result does not mean that `self` cannot be rewritten
|
| 811 |
+
into a form that would be comparable. For example, the
|
| 812 |
+
difference computed below is zero but without simplification
|
| 813 |
+
it does not evaluate to a zero with precision:
|
| 814 |
+
|
| 815 |
+
>>> e = 2**pi*(1 + 2**pi)
|
| 816 |
+
>>> dif = e - e.expand()
|
| 817 |
+
>>> dif.is_comparable
|
| 818 |
+
False
|
| 819 |
+
>>> dif.n(2)._prec
|
| 820 |
+
1
|
| 821 |
+
|
| 822 |
+
"""
|
| 823 |
+
is_extended_real = self.is_extended_real
|
| 824 |
+
if is_extended_real is False:
|
| 825 |
+
return False
|
| 826 |
+
if not self.is_number:
|
| 827 |
+
return False
|
| 828 |
+
# don't re-eval numbers that are already evaluated since
|
| 829 |
+
# this will create spurious precision
|
| 830 |
+
n, i = [p.evalf(2) if not p.is_Number else p
|
| 831 |
+
for p in self.as_real_imag()]
|
| 832 |
+
if not (i.is_Number and n.is_Number):
|
| 833 |
+
return False
|
| 834 |
+
if i:
|
| 835 |
+
# if _prec = 1 we can't decide and if not,
|
| 836 |
+
# the answer is False because numbers with
|
| 837 |
+
# imaginary parts can't be compared
|
| 838 |
+
# so return False
|
| 839 |
+
return False
|
| 840 |
+
else:
|
| 841 |
+
return n._prec != 1
|
| 842 |
+
|
| 843 |
+
@property
|
| 844 |
+
def func(self):
|
| 845 |
+
"""
|
| 846 |
+
The top-level function in an expression.
|
| 847 |
+
|
| 848 |
+
The following should hold for all objects::
|
| 849 |
+
|
| 850 |
+
>> x == x.func(*x.args)
|
| 851 |
+
|
| 852 |
+
Examples
|
| 853 |
+
========
|
| 854 |
+
|
| 855 |
+
>>> from sympy.abc import x
|
| 856 |
+
>>> a = 2*x
|
| 857 |
+
>>> a.func
|
| 858 |
+
<class 'sympy.core.mul.Mul'>
|
| 859 |
+
>>> a.args
|
| 860 |
+
(2, x)
|
| 861 |
+
>>> a.func(*a.args)
|
| 862 |
+
2*x
|
| 863 |
+
>>> a == a.func(*a.args)
|
| 864 |
+
True
|
| 865 |
+
|
| 866 |
+
"""
|
| 867 |
+
return self.__class__
|
| 868 |
+
|
| 869 |
+
@property
|
| 870 |
+
def args(self) -> tuple[Basic, ...]:
|
| 871 |
+
"""Returns a tuple of arguments of 'self'.
|
| 872 |
+
|
| 873 |
+
Examples
|
| 874 |
+
========
|
| 875 |
+
|
| 876 |
+
>>> from sympy import cot
|
| 877 |
+
>>> from sympy.abc import x, y
|
| 878 |
+
|
| 879 |
+
>>> cot(x).args
|
| 880 |
+
(x,)
|
| 881 |
+
|
| 882 |
+
>>> cot(x).args[0]
|
| 883 |
+
x
|
| 884 |
+
|
| 885 |
+
>>> (x*y).args
|
| 886 |
+
(x, y)
|
| 887 |
+
|
| 888 |
+
>>> (x*y).args[1]
|
| 889 |
+
y
|
| 890 |
+
|
| 891 |
+
Notes
|
| 892 |
+
=====
|
| 893 |
+
|
| 894 |
+
Never use self._args, always use self.args.
|
| 895 |
+
Only use _args in __new__ when creating a new function.
|
| 896 |
+
Do not override .args() from Basic (so that it is easy to
|
| 897 |
+
change the interface in the future if needed).
|
| 898 |
+
"""
|
| 899 |
+
return self._args
|
| 900 |
+
|
| 901 |
+
@property
|
| 902 |
+
def _sorted_args(self):
|
| 903 |
+
"""
|
| 904 |
+
The same as ``args``. Derived classes which do not fix an
|
| 905 |
+
order on their arguments should override this method to
|
| 906 |
+
produce the sorted representation.
|
| 907 |
+
"""
|
| 908 |
+
return self.args
|
| 909 |
+
|
| 910 |
+
def as_content_primitive(self, radical=False, clear=True):
|
| 911 |
+
"""A stub to allow Basic args (like Tuple) to be skipped when computing
|
| 912 |
+
the content and primitive components of an expression.
|
| 913 |
+
|
| 914 |
+
See Also
|
| 915 |
+
========
|
| 916 |
+
|
| 917 |
+
sympy.core.expr.Expr.as_content_primitive
|
| 918 |
+
"""
|
| 919 |
+
return S.One, self
|
| 920 |
+
|
| 921 |
+
def subs(self, *args, **kwargs):
|
| 922 |
+
"""
|
| 923 |
+
Substitutes old for new in an expression after sympifying args.
|
| 924 |
+
|
| 925 |
+
`args` is either:
|
| 926 |
+
- two arguments, e.g. foo.subs(old, new)
|
| 927 |
+
- one iterable argument, e.g. foo.subs(iterable). The iterable may be
|
| 928 |
+
o an iterable container with (old, new) pairs. In this case the
|
| 929 |
+
replacements are processed in the order given with successive
|
| 930 |
+
patterns possibly affecting replacements already made.
|
| 931 |
+
o a dict or set whose key/value items correspond to old/new pairs.
|
| 932 |
+
In this case the old/new pairs will be sorted by op count and in
|
| 933 |
+
case of a tie, by number of args and the default_sort_key. The
|
| 934 |
+
resulting sorted list is then processed as an iterable container
|
| 935 |
+
(see previous).
|
| 936 |
+
|
| 937 |
+
If the keyword ``simultaneous`` is True, the subexpressions will not be
|
| 938 |
+
evaluated until all the substitutions have been made.
|
| 939 |
+
|
| 940 |
+
Examples
|
| 941 |
+
========
|
| 942 |
+
|
| 943 |
+
>>> from sympy import pi, exp, limit, oo
|
| 944 |
+
>>> from sympy.abc import x, y
|
| 945 |
+
>>> (1 + x*y).subs(x, pi)
|
| 946 |
+
pi*y + 1
|
| 947 |
+
>>> (1 + x*y).subs({x:pi, y:2})
|
| 948 |
+
1 + 2*pi
|
| 949 |
+
>>> (1 + x*y).subs([(x, pi), (y, 2)])
|
| 950 |
+
1 + 2*pi
|
| 951 |
+
>>> reps = [(y, x**2), (x, 2)]
|
| 952 |
+
>>> (x + y).subs(reps)
|
| 953 |
+
6
|
| 954 |
+
>>> (x + y).subs(reversed(reps))
|
| 955 |
+
x**2 + 2
|
| 956 |
+
|
| 957 |
+
>>> (x**2 + x**4).subs(x**2, y)
|
| 958 |
+
y**2 + y
|
| 959 |
+
|
| 960 |
+
To replace only the x**2 but not the x**4, use xreplace:
|
| 961 |
+
|
| 962 |
+
>>> (x**2 + x**4).xreplace({x**2: y})
|
| 963 |
+
x**4 + y
|
| 964 |
+
|
| 965 |
+
To delay evaluation until all substitutions have been made,
|
| 966 |
+
set the keyword ``simultaneous`` to True:
|
| 967 |
+
|
| 968 |
+
>>> (x/y).subs([(x, 0), (y, 0)])
|
| 969 |
+
0
|
| 970 |
+
>>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True)
|
| 971 |
+
nan
|
| 972 |
+
|
| 973 |
+
This has the added feature of not allowing subsequent substitutions
|
| 974 |
+
to affect those already made:
|
| 975 |
+
|
| 976 |
+
>>> ((x + y)/y).subs({x + y: y, y: x + y})
|
| 977 |
+
1
|
| 978 |
+
>>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True)
|
| 979 |
+
y/(x + y)
|
| 980 |
+
|
| 981 |
+
In order to obtain a canonical result, unordered iterables are
|
| 982 |
+
sorted by count_op length, number of arguments and by the
|
| 983 |
+
default_sort_key to break any ties. All other iterables are left
|
| 984 |
+
unsorted.
|
| 985 |
+
|
| 986 |
+
>>> from sympy import sqrt, sin, cos
|
| 987 |
+
>>> from sympy.abc import a, b, c, d, e
|
| 988 |
+
|
| 989 |
+
>>> A = (sqrt(sin(2*x)), a)
|
| 990 |
+
>>> B = (sin(2*x), b)
|
| 991 |
+
>>> C = (cos(2*x), c)
|
| 992 |
+
>>> D = (x, d)
|
| 993 |
+
>>> E = (exp(x), e)
|
| 994 |
+
|
| 995 |
+
>>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x)
|
| 996 |
+
|
| 997 |
+
>>> expr.subs(dict([A, B, C, D, E]))
|
| 998 |
+
a*c*sin(d*e) + b
|
| 999 |
+
|
| 1000 |
+
The resulting expression represents a literal replacement of the
|
| 1001 |
+
old arguments with the new arguments. This may not reflect the
|
| 1002 |
+
limiting behavior of the expression:
|
| 1003 |
+
|
| 1004 |
+
>>> (x**3 - 3*x).subs({x: oo})
|
| 1005 |
+
nan
|
| 1006 |
+
|
| 1007 |
+
>>> limit(x**3 - 3*x, x, oo)
|
| 1008 |
+
oo
|
| 1009 |
+
|
| 1010 |
+
If the substitution will be followed by numerical
|
| 1011 |
+
evaluation, it is better to pass the substitution to
|
| 1012 |
+
evalf as
|
| 1013 |
+
|
| 1014 |
+
>>> (1/x).evalf(subs={x: 3.0}, n=21)
|
| 1015 |
+
0.333333333333333333333
|
| 1016 |
+
|
| 1017 |
+
rather than
|
| 1018 |
+
|
| 1019 |
+
>>> (1/x).subs({x: 3.0}).evalf(21)
|
| 1020 |
+
0.333333333333333314830
|
| 1021 |
+
|
| 1022 |
+
as the former will ensure that the desired level of precision is
|
| 1023 |
+
obtained.
|
| 1024 |
+
|
| 1025 |
+
See Also
|
| 1026 |
+
========
|
| 1027 |
+
replace: replacement capable of doing wildcard-like matching,
|
| 1028 |
+
parsing of match, and conditional replacements
|
| 1029 |
+
xreplace: exact node replacement in expr tree; also capable of
|
| 1030 |
+
using matching rules
|
| 1031 |
+
sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision
|
| 1032 |
+
|
| 1033 |
+
"""
|
| 1034 |
+
from .containers import Dict
|
| 1035 |
+
from .symbol import Dummy, Symbol
|
| 1036 |
+
from .numbers import _illegal
|
| 1037 |
+
|
| 1038 |
+
unordered = False
|
| 1039 |
+
if len(args) == 1:
|
| 1040 |
+
|
| 1041 |
+
sequence = args[0]
|
| 1042 |
+
if isinstance(sequence, set):
|
| 1043 |
+
unordered = True
|
| 1044 |
+
elif isinstance(sequence, (Dict, Mapping)):
|
| 1045 |
+
unordered = True
|
| 1046 |
+
sequence = sequence.items()
|
| 1047 |
+
elif not iterable(sequence):
|
| 1048 |
+
raise ValueError(filldedent("""
|
| 1049 |
+
When a single argument is passed to subs
|
| 1050 |
+
it should be a dictionary of old: new pairs or an iterable
|
| 1051 |
+
of (old, new) tuples."""))
|
| 1052 |
+
elif len(args) == 2:
|
| 1053 |
+
sequence = [args]
|
| 1054 |
+
else:
|
| 1055 |
+
raise ValueError("subs accepts either 1 or 2 arguments")
|
| 1056 |
+
|
| 1057 |
+
def sympify_old(old):
|
| 1058 |
+
if isinstance(old, str):
|
| 1059 |
+
# Use Symbol rather than parse_expr for old
|
| 1060 |
+
return Symbol(old)
|
| 1061 |
+
elif isinstance(old, type):
|
| 1062 |
+
# Allow a type e.g. Function('f') or sin
|
| 1063 |
+
return sympify(old, strict=False)
|
| 1064 |
+
else:
|
| 1065 |
+
return sympify(old, strict=True)
|
| 1066 |
+
|
| 1067 |
+
def sympify_new(new):
|
| 1068 |
+
if isinstance(new, (str, type)):
|
| 1069 |
+
# Allow a type or parse a string input
|
| 1070 |
+
return sympify(new, strict=False)
|
| 1071 |
+
else:
|
| 1072 |
+
return sympify(new, strict=True)
|
| 1073 |
+
|
| 1074 |
+
sequence = [(sympify_old(s1), sympify_new(s2)) for s1, s2 in sequence]
|
| 1075 |
+
|
| 1076 |
+
# skip if there is no change
|
| 1077 |
+
sequence = [(s1, s2) for s1, s2 in sequence if not _aresame(s1, s2)]
|
| 1078 |
+
|
| 1079 |
+
simultaneous = kwargs.pop('simultaneous', False)
|
| 1080 |
+
|
| 1081 |
+
if unordered:
|
| 1082 |
+
from .sorting import _nodes, default_sort_key
|
| 1083 |
+
sequence = dict(sequence)
|
| 1084 |
+
# order so more complex items are first and items
|
| 1085 |
+
# of identical complexity are ordered so
|
| 1086 |
+
# f(x) < f(y) < x < y
|
| 1087 |
+
# \___ 2 __/ \_1_/ <- number of nodes
|
| 1088 |
+
#
|
| 1089 |
+
# For more complex ordering use an unordered sequence.
|
| 1090 |
+
k = list(ordered(sequence, default=False, keys=(
|
| 1091 |
+
lambda x: -_nodes(x),
|
| 1092 |
+
default_sort_key,
|
| 1093 |
+
)))
|
| 1094 |
+
sequence = [(k, sequence[k]) for k in k]
|
| 1095 |
+
# do infinities first
|
| 1096 |
+
if not simultaneous:
|
| 1097 |
+
redo = [i for i, seq in enumerate(sequence) if seq[1] in _illegal]
|
| 1098 |
+
for i in reversed(redo):
|
| 1099 |
+
sequence.insert(0, sequence.pop(i))
|
| 1100 |
+
|
| 1101 |
+
if simultaneous: # XXX should this be the default for dict subs?
|
| 1102 |
+
reps = {}
|
| 1103 |
+
rv = self
|
| 1104 |
+
kwargs['hack2'] = True
|
| 1105 |
+
m = Dummy('subs_m')
|
| 1106 |
+
for old, new in sequence:
|
| 1107 |
+
com = new.is_commutative
|
| 1108 |
+
if com is None:
|
| 1109 |
+
com = True
|
| 1110 |
+
d = Dummy('subs_d', commutative=com)
|
| 1111 |
+
# using d*m so Subs will be used on dummy variables
|
| 1112 |
+
# in things like Derivative(f(x, y), x) in which x
|
| 1113 |
+
# is both free and bound
|
| 1114 |
+
rv = rv._subs(old, d*m, **kwargs)
|
| 1115 |
+
if not isinstance(rv, Basic):
|
| 1116 |
+
break
|
| 1117 |
+
reps[d] = new
|
| 1118 |
+
reps[m] = S.One # get rid of m
|
| 1119 |
+
return rv.xreplace(reps)
|
| 1120 |
+
else:
|
| 1121 |
+
rv = self
|
| 1122 |
+
for old, new in sequence:
|
| 1123 |
+
rv = rv._subs(old, new, **kwargs)
|
| 1124 |
+
if not isinstance(rv, Basic):
|
| 1125 |
+
break
|
| 1126 |
+
return rv
|
| 1127 |
+
|
| 1128 |
+
@cacheit
|
| 1129 |
+
def _subs(self, old, new, **hints):
|
| 1130 |
+
"""Substitutes an expression old -> new.
|
| 1131 |
+
|
| 1132 |
+
If self is not equal to old then _eval_subs is called.
|
| 1133 |
+
If _eval_subs does not want to make any special replacement
|
| 1134 |
+
then a None is received which indicates that the fallback
|
| 1135 |
+
should be applied wherein a search for replacements is made
|
| 1136 |
+
amongst the arguments of self.
|
| 1137 |
+
|
| 1138 |
+
>>> from sympy import Add
|
| 1139 |
+
>>> from sympy.abc import x, y, z
|
| 1140 |
+
|
| 1141 |
+
Examples
|
| 1142 |
+
========
|
| 1143 |
+
|
| 1144 |
+
Add's _eval_subs knows how to target x + y in the following
|
| 1145 |
+
so it makes the change:
|
| 1146 |
+
|
| 1147 |
+
>>> (x + y + z).subs(x + y, 1)
|
| 1148 |
+
z + 1
|
| 1149 |
+
|
| 1150 |
+
Add's _eval_subs does not need to know how to find x + y in
|
| 1151 |
+
the following:
|
| 1152 |
+
|
| 1153 |
+
>>> Add._eval_subs(z*(x + y) + 3, x + y, 1) is None
|
| 1154 |
+
True
|
| 1155 |
+
|
| 1156 |
+
The returned None will cause the fallback routine to traverse the args and
|
| 1157 |
+
pass the z*(x + y) arg to Mul where the change will take place and the
|
| 1158 |
+
substitution will succeed:
|
| 1159 |
+
|
| 1160 |
+
>>> (z*(x + y) + 3).subs(x + y, 1)
|
| 1161 |
+
z + 3
|
| 1162 |
+
|
| 1163 |
+
** Developers Notes **
|
| 1164 |
+
|
| 1165 |
+
An _eval_subs routine for a class should be written if:
|
| 1166 |
+
|
| 1167 |
+
1) any arguments are not instances of Basic (e.g. bool, tuple);
|
| 1168 |
+
|
| 1169 |
+
2) some arguments should not be targeted (as in integration
|
| 1170 |
+
variables);
|
| 1171 |
+
|
| 1172 |
+
3) if there is something other than a literal replacement
|
| 1173 |
+
that should be attempted (as in Piecewise where the condition
|
| 1174 |
+
may be updated without doing a replacement).
|
| 1175 |
+
|
| 1176 |
+
If it is overridden, here are some special cases that might arise:
|
| 1177 |
+
|
| 1178 |
+
1) If it turns out that no special change was made and all
|
| 1179 |
+
the original sub-arguments should be checked for
|
| 1180 |
+
replacements then None should be returned.
|
| 1181 |
+
|
| 1182 |
+
2) If it is necessary to do substitutions on a portion of
|
| 1183 |
+
the expression then _subs should be called. _subs will
|
| 1184 |
+
handle the case of any sub-expression being equal to old
|
| 1185 |
+
(which usually would not be the case) while its fallback
|
| 1186 |
+
will handle the recursion into the sub-arguments. For
|
| 1187 |
+
example, after Add's _eval_subs removes some matching terms
|
| 1188 |
+
it must process the remaining terms so it calls _subs
|
| 1189 |
+
on each of the un-matched terms and then adds them
|
| 1190 |
+
onto the terms previously obtained.
|
| 1191 |
+
|
| 1192 |
+
3) If the initial expression should remain unchanged then
|
| 1193 |
+
the original expression should be returned. (Whenever an
|
| 1194 |
+
expression is returned, modified or not, no further
|
| 1195 |
+
substitution of old -> new is attempted.) Sum's _eval_subs
|
| 1196 |
+
routine uses this strategy when a substitution is attempted
|
| 1197 |
+
on any of its summation variables.
|
| 1198 |
+
"""
|
| 1199 |
+
|
| 1200 |
+
def fallback(self, old, new):
|
| 1201 |
+
"""
|
| 1202 |
+
Try to replace old with new in any of self's arguments.
|
| 1203 |
+
"""
|
| 1204 |
+
hit = False
|
| 1205 |
+
args = list(self.args)
|
| 1206 |
+
for i, arg in enumerate(args):
|
| 1207 |
+
if not hasattr(arg, '_eval_subs'):
|
| 1208 |
+
continue
|
| 1209 |
+
arg = arg._subs(old, new, **hints)
|
| 1210 |
+
if not _aresame(arg, args[i]):
|
| 1211 |
+
hit = True
|
| 1212 |
+
args[i] = arg
|
| 1213 |
+
if hit:
|
| 1214 |
+
rv = self.func(*args)
|
| 1215 |
+
hack2 = hints.get('hack2', False)
|
| 1216 |
+
if hack2 and self.is_Mul and not rv.is_Mul: # 2-arg hack
|
| 1217 |
+
coeff = S.One
|
| 1218 |
+
nonnumber = []
|
| 1219 |
+
for i in args:
|
| 1220 |
+
if i.is_Number:
|
| 1221 |
+
coeff *= i
|
| 1222 |
+
else:
|
| 1223 |
+
nonnumber.append(i)
|
| 1224 |
+
nonnumber = self.func(*nonnumber)
|
| 1225 |
+
if coeff is S.One:
|
| 1226 |
+
return nonnumber
|
| 1227 |
+
else:
|
| 1228 |
+
return self.func(coeff, nonnumber, evaluate=False)
|
| 1229 |
+
return rv
|
| 1230 |
+
return self
|
| 1231 |
+
|
| 1232 |
+
if _aresame(self, old):
|
| 1233 |
+
return new
|
| 1234 |
+
|
| 1235 |
+
rv = self._eval_subs(old, new)
|
| 1236 |
+
if rv is None:
|
| 1237 |
+
rv = fallback(self, old, new)
|
| 1238 |
+
return rv
|
| 1239 |
+
|
| 1240 |
+
def _eval_subs(self, old, new):
|
| 1241 |
+
"""Override this stub if you want to do anything more than
|
| 1242 |
+
attempt a replacement of old with new in the arguments of self.
|
| 1243 |
+
|
| 1244 |
+
See also
|
| 1245 |
+
========
|
| 1246 |
+
|
| 1247 |
+
_subs
|
| 1248 |
+
"""
|
| 1249 |
+
return None
|
| 1250 |
+
|
| 1251 |
+
def xreplace(self, rule):
|
| 1252 |
+
"""
|
| 1253 |
+
Replace occurrences of objects within the expression.
|
| 1254 |
+
|
| 1255 |
+
Parameters
|
| 1256 |
+
==========
|
| 1257 |
+
|
| 1258 |
+
rule : dict-like
|
| 1259 |
+
Expresses a replacement rule
|
| 1260 |
+
|
| 1261 |
+
Returns
|
| 1262 |
+
=======
|
| 1263 |
+
|
| 1264 |
+
xreplace : the result of the replacement
|
| 1265 |
+
|
| 1266 |
+
Examples
|
| 1267 |
+
========
|
| 1268 |
+
|
| 1269 |
+
>>> from sympy import symbols, pi, exp
|
| 1270 |
+
>>> x, y, z = symbols('x y z')
|
| 1271 |
+
>>> (1 + x*y).xreplace({x: pi})
|
| 1272 |
+
pi*y + 1
|
| 1273 |
+
>>> (1 + x*y).xreplace({x: pi, y: 2})
|
| 1274 |
+
1 + 2*pi
|
| 1275 |
+
|
| 1276 |
+
Replacements occur only if an entire node in the expression tree is
|
| 1277 |
+
matched:
|
| 1278 |
+
|
| 1279 |
+
>>> (x*y + z).xreplace({x*y: pi})
|
| 1280 |
+
z + pi
|
| 1281 |
+
>>> (x*y*z).xreplace({x*y: pi})
|
| 1282 |
+
x*y*z
|
| 1283 |
+
>>> (2*x).xreplace({2*x: y, x: z})
|
| 1284 |
+
y
|
| 1285 |
+
>>> (2*2*x).xreplace({2*x: y, x: z})
|
| 1286 |
+
4*z
|
| 1287 |
+
>>> (x + y + 2).xreplace({x + y: 2})
|
| 1288 |
+
x + y + 2
|
| 1289 |
+
>>> (x + 2 + exp(x + 2)).xreplace({x + 2: y})
|
| 1290 |
+
x + exp(y) + 2
|
| 1291 |
+
|
| 1292 |
+
xreplace does not differentiate between free and bound symbols. In the
|
| 1293 |
+
following, subs(x, y) would not change x since it is a bound symbol,
|
| 1294 |
+
but xreplace does:
|
| 1295 |
+
|
| 1296 |
+
>>> from sympy import Integral
|
| 1297 |
+
>>> Integral(x, (x, 1, 2*x)).xreplace({x: y})
|
| 1298 |
+
Integral(y, (y, 1, 2*y))
|
| 1299 |
+
|
| 1300 |
+
Trying to replace x with an expression raises an error:
|
| 1301 |
+
|
| 1302 |
+
>>> Integral(x, (x, 1, 2*x)).xreplace({x: 2*y}) # doctest: +SKIP
|
| 1303 |
+
ValueError: Invalid limits given: ((2*y, 1, 4*y),)
|
| 1304 |
+
|
| 1305 |
+
See Also
|
| 1306 |
+
========
|
| 1307 |
+
replace: replacement capable of doing wildcard-like matching,
|
| 1308 |
+
parsing of match, and conditional replacements
|
| 1309 |
+
subs: substitution of subexpressions as defined by the objects
|
| 1310 |
+
themselves.
|
| 1311 |
+
|
| 1312 |
+
"""
|
| 1313 |
+
value, _ = self._xreplace(rule)
|
| 1314 |
+
return value
|
| 1315 |
+
|
| 1316 |
+
def _xreplace(self, rule):
|
| 1317 |
+
"""
|
| 1318 |
+
Helper for xreplace. Tracks whether a replacement actually occurred.
|
| 1319 |
+
"""
|
| 1320 |
+
if self in rule:
|
| 1321 |
+
return rule[self], True
|
| 1322 |
+
elif rule:
|
| 1323 |
+
args = []
|
| 1324 |
+
changed = False
|
| 1325 |
+
for a in self.args:
|
| 1326 |
+
_xreplace = getattr(a, '_xreplace', None)
|
| 1327 |
+
if _xreplace is not None:
|
| 1328 |
+
a_xr = _xreplace(rule)
|
| 1329 |
+
args.append(a_xr[0])
|
| 1330 |
+
changed |= a_xr[1]
|
| 1331 |
+
else:
|
| 1332 |
+
args.append(a)
|
| 1333 |
+
args = tuple(args)
|
| 1334 |
+
if changed:
|
| 1335 |
+
return self.func(*args), True
|
| 1336 |
+
return self, False
|
| 1337 |
+
|
| 1338 |
+
@cacheit
|
| 1339 |
+
def has(self, *patterns):
|
| 1340 |
+
"""
|
| 1341 |
+
Test whether any subexpression matches any of the patterns.
|
| 1342 |
+
|
| 1343 |
+
Examples
|
| 1344 |
+
========
|
| 1345 |
+
|
| 1346 |
+
>>> from sympy import sin
|
| 1347 |
+
>>> from sympy.abc import x, y, z
|
| 1348 |
+
>>> (x**2 + sin(x*y)).has(z)
|
| 1349 |
+
False
|
| 1350 |
+
>>> (x**2 + sin(x*y)).has(x, y, z)
|
| 1351 |
+
True
|
| 1352 |
+
>>> x.has(x)
|
| 1353 |
+
True
|
| 1354 |
+
|
| 1355 |
+
Note ``has`` is a structural algorithm with no knowledge of
|
| 1356 |
+
mathematics. Consider the following half-open interval:
|
| 1357 |
+
|
| 1358 |
+
>>> from sympy import Interval
|
| 1359 |
+
>>> i = Interval.Lopen(0, 5); i
|
| 1360 |
+
Interval.Lopen(0, 5)
|
| 1361 |
+
>>> i.args
|
| 1362 |
+
(0, 5, True, False)
|
| 1363 |
+
>>> i.has(4) # there is no "4" in the arguments
|
| 1364 |
+
False
|
| 1365 |
+
>>> i.has(0) # there *is* a "0" in the arguments
|
| 1366 |
+
True
|
| 1367 |
+
|
| 1368 |
+
Instead, use ``contains`` to determine whether a number is in the
|
| 1369 |
+
interval or not:
|
| 1370 |
+
|
| 1371 |
+
>>> i.contains(4)
|
| 1372 |
+
True
|
| 1373 |
+
>>> i.contains(0)
|
| 1374 |
+
False
|
| 1375 |
+
|
| 1376 |
+
|
| 1377 |
+
Note that ``expr.has(*patterns)`` is exactly equivalent to
|
| 1378 |
+
``any(expr.has(p) for p in patterns)``. In particular, ``False`` is
|
| 1379 |
+
returned when the list of patterns is empty.
|
| 1380 |
+
|
| 1381 |
+
>>> x.has()
|
| 1382 |
+
False
|
| 1383 |
+
|
| 1384 |
+
"""
|
| 1385 |
+
return self._has(iterargs, *patterns)
|
| 1386 |
+
|
| 1387 |
+
def has_xfree(self, s: set[Basic]):
|
| 1388 |
+
"""Return True if self has any of the patterns in s as a
|
| 1389 |
+
free argument, else False. This is like `Basic.has_free`
|
| 1390 |
+
but this will only report exact argument matches.
|
| 1391 |
+
|
| 1392 |
+
Examples
|
| 1393 |
+
========
|
| 1394 |
+
|
| 1395 |
+
>>> from sympy import Function
|
| 1396 |
+
>>> from sympy.abc import x, y
|
| 1397 |
+
>>> f = Function('f')
|
| 1398 |
+
>>> f(x).has_xfree({f})
|
| 1399 |
+
False
|
| 1400 |
+
>>> f(x).has_xfree({f(x)})
|
| 1401 |
+
True
|
| 1402 |
+
>>> f(x + 1).has_xfree({x})
|
| 1403 |
+
True
|
| 1404 |
+
>>> f(x + 1).has_xfree({x + 1})
|
| 1405 |
+
True
|
| 1406 |
+
>>> f(x + y + 1).has_xfree({x + 1})
|
| 1407 |
+
False
|
| 1408 |
+
"""
|
| 1409 |
+
# protect O(1) containment check by requiring:
|
| 1410 |
+
if type(s) is not set:
|
| 1411 |
+
raise TypeError('expecting set argument')
|
| 1412 |
+
return any(a in s for a in iterfreeargs(self))
|
| 1413 |
+
|
| 1414 |
+
@cacheit
|
| 1415 |
+
def has_free(self, *patterns):
|
| 1416 |
+
"""Return True if self has object(s) ``x`` as a free expression
|
| 1417 |
+
else False.
|
| 1418 |
+
|
| 1419 |
+
Examples
|
| 1420 |
+
========
|
| 1421 |
+
|
| 1422 |
+
>>> from sympy import Integral, Function
|
| 1423 |
+
>>> from sympy.abc import x, y
|
| 1424 |
+
>>> f = Function('f')
|
| 1425 |
+
>>> g = Function('g')
|
| 1426 |
+
>>> expr = Integral(f(x), (f(x), 1, g(y)))
|
| 1427 |
+
>>> expr.free_symbols
|
| 1428 |
+
{y}
|
| 1429 |
+
>>> expr.has_free(g(y))
|
| 1430 |
+
True
|
| 1431 |
+
>>> expr.has_free(*(x, f(x)))
|
| 1432 |
+
False
|
| 1433 |
+
|
| 1434 |
+
This works for subexpressions and types, too:
|
| 1435 |
+
|
| 1436 |
+
>>> expr.has_free(g)
|
| 1437 |
+
True
|
| 1438 |
+
>>> (x + y + 1).has_free(y + 1)
|
| 1439 |
+
True
|
| 1440 |
+
"""
|
| 1441 |
+
if not patterns:
|
| 1442 |
+
return False
|
| 1443 |
+
p0 = patterns[0]
|
| 1444 |
+
if len(patterns) == 1 and iterable(p0) and not isinstance(p0, Basic):
|
| 1445 |
+
# Basic can contain iterables (though not non-Basic, ideally)
|
| 1446 |
+
# but don't encourage mixed passing patterns
|
| 1447 |
+
raise TypeError(filldedent('''
|
| 1448 |
+
Expecting 1 or more Basic args, not a single
|
| 1449 |
+
non-Basic iterable. Don't forget to unpack
|
| 1450 |
+
iterables: `eq.has_free(*patterns)`'''))
|
| 1451 |
+
# try quick test first
|
| 1452 |
+
s = set(patterns)
|
| 1453 |
+
rv = self.has_xfree(s)
|
| 1454 |
+
if rv:
|
| 1455 |
+
return rv
|
| 1456 |
+
# now try matching through slower _has
|
| 1457 |
+
return self._has(iterfreeargs, *patterns)
|
| 1458 |
+
|
| 1459 |
+
def _has(self, iterargs, *patterns):
|
| 1460 |
+
# separate out types and unhashable objects
|
| 1461 |
+
type_set = set() # only types
|
| 1462 |
+
p_set = set() # hashable non-types
|
| 1463 |
+
for p in patterns:
|
| 1464 |
+
if isinstance(p, type) and issubclass(p, Basic):
|
| 1465 |
+
type_set.add(p)
|
| 1466 |
+
continue
|
| 1467 |
+
if not isinstance(p, Basic):
|
| 1468 |
+
try:
|
| 1469 |
+
p = _sympify(p)
|
| 1470 |
+
except SympifyError:
|
| 1471 |
+
continue # Basic won't have this in it
|
| 1472 |
+
p_set.add(p) # fails if object defines __eq__ but
|
| 1473 |
+
# doesn't define __hash__
|
| 1474 |
+
types = tuple(type_set) #
|
| 1475 |
+
for i in iterargs(self): #
|
| 1476 |
+
if i in p_set: # <--- here, too
|
| 1477 |
+
return True
|
| 1478 |
+
if isinstance(i, types):
|
| 1479 |
+
return True
|
| 1480 |
+
|
| 1481 |
+
# use matcher if defined, e.g. operations defines
|
| 1482 |
+
# matcher that checks for exact subset containment,
|
| 1483 |
+
# (x + y + 1).has(x + 1) -> True
|
| 1484 |
+
for i in p_set - type_set: # types don't have matchers
|
| 1485 |
+
if not hasattr(i, '_has_matcher'):
|
| 1486 |
+
continue
|
| 1487 |
+
match = i._has_matcher()
|
| 1488 |
+
if any(match(arg) for arg in iterargs(self)):
|
| 1489 |
+
return True
|
| 1490 |
+
|
| 1491 |
+
# no success
|
| 1492 |
+
return False
|
| 1493 |
+
|
| 1494 |
+
def replace(self, query, value, map=False, simultaneous=True, exact=None):
|
| 1495 |
+
"""
|
| 1496 |
+
Replace matching subexpressions of ``self`` with ``value``.
|
| 1497 |
+
|
| 1498 |
+
If ``map = True`` then also return the mapping {old: new} where ``old``
|
| 1499 |
+
was a sub-expression found with query and ``new`` is the replacement
|
| 1500 |
+
value for it. If the expression itself does not match the query, then
|
| 1501 |
+
the returned value will be ``self.xreplace(map)`` otherwise it should
|
| 1502 |
+
be ``self.subs(ordered(map.items()))``.
|
| 1503 |
+
|
| 1504 |
+
Traverses an expression tree and performs replacement of matching
|
| 1505 |
+
subexpressions from the bottom to the top of the tree. The default
|
| 1506 |
+
approach is to do the replacement in a simultaneous fashion so
|
| 1507 |
+
changes made are targeted only once. If this is not desired or causes
|
| 1508 |
+
problems, ``simultaneous`` can be set to False.
|
| 1509 |
+
|
| 1510 |
+
In addition, if an expression containing more than one Wild symbol
|
| 1511 |
+
is being used to match subexpressions and the ``exact`` flag is None
|
| 1512 |
+
it will be set to True so the match will only succeed if all non-zero
|
| 1513 |
+
values are received for each Wild that appears in the match pattern.
|
| 1514 |
+
Setting this to False accepts a match of 0; while setting it True
|
| 1515 |
+
accepts all matches that have a 0 in them. See example below for
|
| 1516 |
+
cautions.
|
| 1517 |
+
|
| 1518 |
+
The list of possible combinations of queries and replacement values
|
| 1519 |
+
is listed below:
|
| 1520 |
+
|
| 1521 |
+
Examples
|
| 1522 |
+
========
|
| 1523 |
+
|
| 1524 |
+
Initial setup
|
| 1525 |
+
|
| 1526 |
+
>>> from sympy import log, sin, cos, tan, Wild, Mul, Add
|
| 1527 |
+
>>> from sympy.abc import x, y
|
| 1528 |
+
>>> f = log(sin(x)) + tan(sin(x**2))
|
| 1529 |
+
|
| 1530 |
+
1.1. type -> type
|
| 1531 |
+
obj.replace(type, newtype)
|
| 1532 |
+
|
| 1533 |
+
When object of type ``type`` is found, replace it with the
|
| 1534 |
+
result of passing its argument(s) to ``newtype``.
|
| 1535 |
+
|
| 1536 |
+
>>> f.replace(sin, cos)
|
| 1537 |
+
log(cos(x)) + tan(cos(x**2))
|
| 1538 |
+
>>> sin(x).replace(sin, cos, map=True)
|
| 1539 |
+
(cos(x), {sin(x): cos(x)})
|
| 1540 |
+
>>> (x*y).replace(Mul, Add)
|
| 1541 |
+
x + y
|
| 1542 |
+
|
| 1543 |
+
1.2. type -> func
|
| 1544 |
+
obj.replace(type, func)
|
| 1545 |
+
|
| 1546 |
+
When object of type ``type`` is found, apply ``func`` to its
|
| 1547 |
+
argument(s). ``func`` must be written to handle the number
|
| 1548 |
+
of arguments of ``type``.
|
| 1549 |
+
|
| 1550 |
+
>>> f.replace(sin, lambda arg: sin(2*arg))
|
| 1551 |
+
log(sin(2*x)) + tan(sin(2*x**2))
|
| 1552 |
+
>>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args)))
|
| 1553 |
+
sin(2*x*y)
|
| 1554 |
+
|
| 1555 |
+
2.1. pattern -> expr
|
| 1556 |
+
obj.replace(pattern(wild), expr(wild))
|
| 1557 |
+
|
| 1558 |
+
Replace subexpressions matching ``pattern`` with the expression
|
| 1559 |
+
written in terms of the Wild symbols in ``pattern``.
|
| 1560 |
+
|
| 1561 |
+
>>> a, b = map(Wild, 'ab')
|
| 1562 |
+
>>> f.replace(sin(a), tan(a))
|
| 1563 |
+
log(tan(x)) + tan(tan(x**2))
|
| 1564 |
+
>>> f.replace(sin(a), tan(a/2))
|
| 1565 |
+
log(tan(x/2)) + tan(tan(x**2/2))
|
| 1566 |
+
>>> f.replace(sin(a), a)
|
| 1567 |
+
log(x) + tan(x**2)
|
| 1568 |
+
>>> (x*y).replace(a*x, a)
|
| 1569 |
+
y
|
| 1570 |
+
|
| 1571 |
+
Matching is exact by default when more than one Wild symbol
|
| 1572 |
+
is used: matching fails unless the match gives non-zero
|
| 1573 |
+
values for all Wild symbols:
|
| 1574 |
+
|
| 1575 |
+
>>> (2*x + y).replace(a*x + b, b - a)
|
| 1576 |
+
y - 2
|
| 1577 |
+
>>> (2*x).replace(a*x + b, b - a)
|
| 1578 |
+
2*x
|
| 1579 |
+
|
| 1580 |
+
When set to False, the results may be non-intuitive:
|
| 1581 |
+
|
| 1582 |
+
>>> (2*x).replace(a*x + b, b - a, exact=False)
|
| 1583 |
+
2/x
|
| 1584 |
+
|
| 1585 |
+
2.2. pattern -> func
|
| 1586 |
+
obj.replace(pattern(wild), lambda wild: expr(wild))
|
| 1587 |
+
|
| 1588 |
+
All behavior is the same as in 2.1 but now a function in terms of
|
| 1589 |
+
pattern variables is used rather than an expression:
|
| 1590 |
+
|
| 1591 |
+
>>> f.replace(sin(a), lambda a: sin(2*a))
|
| 1592 |
+
log(sin(2*x)) + tan(sin(2*x**2))
|
| 1593 |
+
|
| 1594 |
+
3.1. func -> func
|
| 1595 |
+
obj.replace(filter, func)
|
| 1596 |
+
|
| 1597 |
+
Replace subexpression ``e`` with ``func(e)`` if ``filter(e)``
|
| 1598 |
+
is True.
|
| 1599 |
+
|
| 1600 |
+
>>> g = 2*sin(x**3)
|
| 1601 |
+
>>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2)
|
| 1602 |
+
4*sin(x**9)
|
| 1603 |
+
|
| 1604 |
+
The expression itself is also targeted by the query but is done in
|
| 1605 |
+
such a fashion that changes are not made twice.
|
| 1606 |
+
|
| 1607 |
+
>>> e = x*(x*y + 1)
|
| 1608 |
+
>>> e.replace(lambda x: x.is_Mul, lambda x: 2*x)
|
| 1609 |
+
2*x*(2*x*y + 1)
|
| 1610 |
+
|
| 1611 |
+
When matching a single symbol, `exact` will default to True, but
|
| 1612 |
+
this may or may not be the behavior that is desired:
|
| 1613 |
+
|
| 1614 |
+
Here, we want `exact=False`:
|
| 1615 |
+
|
| 1616 |
+
>>> from sympy import Function
|
| 1617 |
+
>>> f = Function('f')
|
| 1618 |
+
>>> e = f(1) + f(0)
|
| 1619 |
+
>>> q = f(a), lambda a: f(a + 1)
|
| 1620 |
+
>>> e.replace(*q, exact=False)
|
| 1621 |
+
f(1) + f(2)
|
| 1622 |
+
>>> e.replace(*q, exact=True)
|
| 1623 |
+
f(0) + f(2)
|
| 1624 |
+
|
| 1625 |
+
But here, the nature of matching makes selecting
|
| 1626 |
+
the right setting tricky:
|
| 1627 |
+
|
| 1628 |
+
>>> e = x**(1 + y)
|
| 1629 |
+
>>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=False)
|
| 1630 |
+
x
|
| 1631 |
+
>>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=True)
|
| 1632 |
+
x**(-x - y + 1)
|
| 1633 |
+
>>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=False)
|
| 1634 |
+
x
|
| 1635 |
+
>>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=True)
|
| 1636 |
+
x**(1 - y)
|
| 1637 |
+
|
| 1638 |
+
It is probably better to use a different form of the query
|
| 1639 |
+
that describes the target expression more precisely:
|
| 1640 |
+
|
| 1641 |
+
>>> (1 + x**(1 + y)).replace(
|
| 1642 |
+
... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1,
|
| 1643 |
+
... lambda x: x.base**(1 - (x.exp - 1)))
|
| 1644 |
+
...
|
| 1645 |
+
x**(1 - y) + 1
|
| 1646 |
+
|
| 1647 |
+
See Also
|
| 1648 |
+
========
|
| 1649 |
+
|
| 1650 |
+
subs: substitution of subexpressions as defined by the objects
|
| 1651 |
+
themselves.
|
| 1652 |
+
xreplace: exact node replacement in expr tree; also capable of
|
| 1653 |
+
using matching rules
|
| 1654 |
+
|
| 1655 |
+
"""
|
| 1656 |
+
|
| 1657 |
+
try:
|
| 1658 |
+
query = _sympify(query)
|
| 1659 |
+
except SympifyError:
|
| 1660 |
+
pass
|
| 1661 |
+
try:
|
| 1662 |
+
value = _sympify(value)
|
| 1663 |
+
except SympifyError:
|
| 1664 |
+
pass
|
| 1665 |
+
if isinstance(query, type):
|
| 1666 |
+
_query = lambda expr: isinstance(expr, query)
|
| 1667 |
+
|
| 1668 |
+
if isinstance(value, type):
|
| 1669 |
+
_value = lambda expr, result: value(*expr.args)
|
| 1670 |
+
elif callable(value):
|
| 1671 |
+
_value = lambda expr, result: value(*expr.args)
|
| 1672 |
+
else:
|
| 1673 |
+
raise TypeError(
|
| 1674 |
+
"given a type, replace() expects another "
|
| 1675 |
+
"type or a callable")
|
| 1676 |
+
elif isinstance(query, Basic):
|
| 1677 |
+
_query = lambda expr: expr.match(query)
|
| 1678 |
+
if exact is None:
|
| 1679 |
+
from .symbol import Wild
|
| 1680 |
+
exact = (len(query.atoms(Wild)) > 1)
|
| 1681 |
+
|
| 1682 |
+
if isinstance(value, Basic):
|
| 1683 |
+
if exact:
|
| 1684 |
+
_value = lambda expr, result: (value.subs(result)
|
| 1685 |
+
if all(result.values()) else expr)
|
| 1686 |
+
else:
|
| 1687 |
+
_value = lambda expr, result: value.subs(result)
|
| 1688 |
+
elif callable(value):
|
| 1689 |
+
# match dictionary keys get the trailing underscore stripped
|
| 1690 |
+
# from them and are then passed as keywords to the callable;
|
| 1691 |
+
# if ``exact`` is True, only accept match if there are no null
|
| 1692 |
+
# values amongst those matched.
|
| 1693 |
+
if exact:
|
| 1694 |
+
_value = lambda expr, result: (value(**
|
| 1695 |
+
{str(k)[:-1]: v for k, v in result.items()})
|
| 1696 |
+
if all(val for val in result.values()) else expr)
|
| 1697 |
+
else:
|
| 1698 |
+
_value = lambda expr, result: value(**
|
| 1699 |
+
{str(k)[:-1]: v for k, v in result.items()})
|
| 1700 |
+
else:
|
| 1701 |
+
raise TypeError(
|
| 1702 |
+
"given an expression, replace() expects "
|
| 1703 |
+
"another expression or a callable")
|
| 1704 |
+
elif callable(query):
|
| 1705 |
+
_query = query
|
| 1706 |
+
|
| 1707 |
+
if callable(value):
|
| 1708 |
+
_value = lambda expr, result: value(expr)
|
| 1709 |
+
else:
|
| 1710 |
+
raise TypeError(
|
| 1711 |
+
"given a callable, replace() expects "
|
| 1712 |
+
"another callable")
|
| 1713 |
+
else:
|
| 1714 |
+
raise TypeError(
|
| 1715 |
+
"first argument to replace() must be a "
|
| 1716 |
+
"type, an expression or a callable")
|
| 1717 |
+
|
| 1718 |
+
def walk(rv, F):
|
| 1719 |
+
"""Apply ``F`` to args and then to result.
|
| 1720 |
+
"""
|
| 1721 |
+
args = getattr(rv, 'args', None)
|
| 1722 |
+
if args is not None:
|
| 1723 |
+
if args:
|
| 1724 |
+
newargs = tuple([walk(a, F) for a in args])
|
| 1725 |
+
if args != newargs:
|
| 1726 |
+
rv = rv.func(*newargs)
|
| 1727 |
+
if simultaneous:
|
| 1728 |
+
# if rv is something that was already
|
| 1729 |
+
# matched (that was changed) then skip
|
| 1730 |
+
# applying F again
|
| 1731 |
+
for i, e in enumerate(args):
|
| 1732 |
+
if rv == e and e != newargs[i]:
|
| 1733 |
+
return rv
|
| 1734 |
+
rv = F(rv)
|
| 1735 |
+
return rv
|
| 1736 |
+
|
| 1737 |
+
mapping = {} # changes that took place
|
| 1738 |
+
|
| 1739 |
+
def rec_replace(expr):
|
| 1740 |
+
result = _query(expr)
|
| 1741 |
+
if result or result == {}:
|
| 1742 |
+
v = _value(expr, result)
|
| 1743 |
+
if v is not None and v != expr:
|
| 1744 |
+
if map:
|
| 1745 |
+
mapping[expr] = v
|
| 1746 |
+
expr = v
|
| 1747 |
+
return expr
|
| 1748 |
+
|
| 1749 |
+
rv = walk(self, rec_replace)
|
| 1750 |
+
return (rv, mapping) if map else rv
|
| 1751 |
+
|
| 1752 |
+
def find(self, query, group=False):
|
| 1753 |
+
"""Find all subexpressions matching a query."""
|
| 1754 |
+
query = _make_find_query(query)
|
| 1755 |
+
results = list(filter(query, _preorder_traversal(self)))
|
| 1756 |
+
|
| 1757 |
+
if not group:
|
| 1758 |
+
return set(results)
|
| 1759 |
+
else:
|
| 1760 |
+
groups = {}
|
| 1761 |
+
|
| 1762 |
+
for result in results:
|
| 1763 |
+
if result in groups:
|
| 1764 |
+
groups[result] += 1
|
| 1765 |
+
else:
|
| 1766 |
+
groups[result] = 1
|
| 1767 |
+
|
| 1768 |
+
return groups
|
| 1769 |
+
|
| 1770 |
+
def count(self, query):
|
| 1771 |
+
"""Count the number of matching subexpressions."""
|
| 1772 |
+
query = _make_find_query(query)
|
| 1773 |
+
return sum(bool(query(sub)) for sub in _preorder_traversal(self))
|
| 1774 |
+
|
| 1775 |
+
def matches(self, expr, repl_dict=None, old=False):
|
| 1776 |
+
"""
|
| 1777 |
+
Helper method for match() that looks for a match between Wild symbols
|
| 1778 |
+
in self and expressions in expr.
|
| 1779 |
+
|
| 1780 |
+
Examples
|
| 1781 |
+
========
|
| 1782 |
+
|
| 1783 |
+
>>> from sympy import symbols, Wild, Basic
|
| 1784 |
+
>>> a, b, c = symbols('a b c')
|
| 1785 |
+
>>> x = Wild('x')
|
| 1786 |
+
>>> Basic(a + x, x).matches(Basic(a + b, c)) is None
|
| 1787 |
+
True
|
| 1788 |
+
>>> Basic(a + x, x).matches(Basic(a + b + c, b + c))
|
| 1789 |
+
{x_: b + c}
|
| 1790 |
+
"""
|
| 1791 |
+
expr = sympify(expr)
|
| 1792 |
+
if not isinstance(expr, self.__class__):
|
| 1793 |
+
return None
|
| 1794 |
+
|
| 1795 |
+
if repl_dict is None:
|
| 1796 |
+
repl_dict = {}
|
| 1797 |
+
else:
|
| 1798 |
+
repl_dict = repl_dict.copy()
|
| 1799 |
+
|
| 1800 |
+
if self == expr:
|
| 1801 |
+
return repl_dict
|
| 1802 |
+
|
| 1803 |
+
if len(self.args) != len(expr.args):
|
| 1804 |
+
return None
|
| 1805 |
+
|
| 1806 |
+
d = repl_dict # already a copy
|
| 1807 |
+
for arg, other_arg in zip(self.args, expr.args):
|
| 1808 |
+
if arg == other_arg:
|
| 1809 |
+
continue
|
| 1810 |
+
if arg.is_Relational:
|
| 1811 |
+
try:
|
| 1812 |
+
d = arg.xreplace(d).matches(other_arg, d, old=old)
|
| 1813 |
+
except TypeError: # Should be InvalidComparisonError when introduced
|
| 1814 |
+
d = None
|
| 1815 |
+
else:
|
| 1816 |
+
d = arg.xreplace(d).matches(other_arg, d, old=old)
|
| 1817 |
+
if d is None:
|
| 1818 |
+
return None
|
| 1819 |
+
return d
|
| 1820 |
+
|
| 1821 |
+
def match(self, pattern, old=False):
|
| 1822 |
+
"""
|
| 1823 |
+
Pattern matching.
|
| 1824 |
+
|
| 1825 |
+
Wild symbols match all.
|
| 1826 |
+
|
| 1827 |
+
Return ``None`` when expression (self) does not match
|
| 1828 |
+
with pattern. Otherwise return a dictionary such that::
|
| 1829 |
+
|
| 1830 |
+
pattern.xreplace(self.match(pattern)) == self
|
| 1831 |
+
|
| 1832 |
+
Examples
|
| 1833 |
+
========
|
| 1834 |
+
|
| 1835 |
+
>>> from sympy import Wild, Sum
|
| 1836 |
+
>>> from sympy.abc import x, y
|
| 1837 |
+
>>> p = Wild("p")
|
| 1838 |
+
>>> q = Wild("q")
|
| 1839 |
+
>>> r = Wild("r")
|
| 1840 |
+
>>> e = (x+y)**(x+y)
|
| 1841 |
+
>>> e.match(p**p)
|
| 1842 |
+
{p_: x + y}
|
| 1843 |
+
>>> e.match(p**q)
|
| 1844 |
+
{p_: x + y, q_: x + y}
|
| 1845 |
+
>>> e = (2*x)**2
|
| 1846 |
+
>>> e.match(p*q**r)
|
| 1847 |
+
{p_: 4, q_: x, r_: 2}
|
| 1848 |
+
>>> (p*q**r).xreplace(e.match(p*q**r))
|
| 1849 |
+
4*x**2
|
| 1850 |
+
|
| 1851 |
+
Structurally bound symbols are ignored during matching:
|
| 1852 |
+
|
| 1853 |
+
>>> Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, p)))
|
| 1854 |
+
{p_: 2}
|
| 1855 |
+
|
| 1856 |
+
But they can be identified if desired:
|
| 1857 |
+
|
| 1858 |
+
>>> Sum(x, (x, 1, 2)).match(Sum(q, (q, 1, p)))
|
| 1859 |
+
{p_: 2, q_: x}
|
| 1860 |
+
|
| 1861 |
+
The ``old`` flag will give the old-style pattern matching where
|
| 1862 |
+
expressions and patterns are essentially solved to give the
|
| 1863 |
+
match. Both of the following give None unless ``old=True``:
|
| 1864 |
+
|
| 1865 |
+
>>> (x - 2).match(p - x, old=True)
|
| 1866 |
+
{p_: 2*x - 2}
|
| 1867 |
+
>>> (2/x).match(p*x, old=True)
|
| 1868 |
+
{p_: 2/x**2}
|
| 1869 |
+
|
| 1870 |
+
"""
|
| 1871 |
+
pattern = sympify(pattern)
|
| 1872 |
+
# match non-bound symbols
|
| 1873 |
+
canonical = lambda x: x if x.is_Symbol else x.as_dummy()
|
| 1874 |
+
m = canonical(pattern).matches(canonical(self), old=old)
|
| 1875 |
+
if m is None:
|
| 1876 |
+
return m
|
| 1877 |
+
from .symbol import Wild
|
| 1878 |
+
from .function import WildFunction
|
| 1879 |
+
from ..tensor.tensor import WildTensor, WildTensorIndex, WildTensorHead
|
| 1880 |
+
wild = pattern.atoms(Wild, WildFunction, WildTensor, WildTensorIndex, WildTensorHead)
|
| 1881 |
+
# sanity check
|
| 1882 |
+
if set(m) - wild:
|
| 1883 |
+
raise ValueError(filldedent('''
|
| 1884 |
+
Some `matches` routine did not use a copy of repl_dict
|
| 1885 |
+
and injected unexpected symbols. Report this as an
|
| 1886 |
+
error at https://github.com/sympy/sympy/issues'''))
|
| 1887 |
+
# now see if bound symbols were requested
|
| 1888 |
+
bwild = wild - set(m)
|
| 1889 |
+
if not bwild:
|
| 1890 |
+
return m
|
| 1891 |
+
# replace free-Wild symbols in pattern with match result
|
| 1892 |
+
# so they will match but not be in the next match
|
| 1893 |
+
wpat = pattern.xreplace(m)
|
| 1894 |
+
# identify remaining bound wild
|
| 1895 |
+
w = wpat.matches(self, old=old)
|
| 1896 |
+
# add them to m
|
| 1897 |
+
if w:
|
| 1898 |
+
m.update(w)
|
| 1899 |
+
# done
|
| 1900 |
+
return m
|
| 1901 |
+
|
| 1902 |
+
def count_ops(self, visual=None):
|
| 1903 |
+
"""Wrapper for count_ops that returns the operation count."""
|
| 1904 |
+
from .function import count_ops
|
| 1905 |
+
return count_ops(self, visual)
|
| 1906 |
+
|
| 1907 |
+
def doit(self, **hints):
|
| 1908 |
+
"""Evaluate objects that are not evaluated by default like limits,
|
| 1909 |
+
integrals, sums and products. All objects of this kind will be
|
| 1910 |
+
evaluated recursively, unless some species were excluded via 'hints'
|
| 1911 |
+
or unless the 'deep' hint was set to 'False'.
|
| 1912 |
+
|
| 1913 |
+
>>> from sympy import Integral
|
| 1914 |
+
>>> from sympy.abc import x
|
| 1915 |
+
|
| 1916 |
+
>>> 2*Integral(x, x)
|
| 1917 |
+
2*Integral(x, x)
|
| 1918 |
+
|
| 1919 |
+
>>> (2*Integral(x, x)).doit()
|
| 1920 |
+
x**2
|
| 1921 |
+
|
| 1922 |
+
>>> (2*Integral(x, x)).doit(deep=False)
|
| 1923 |
+
2*Integral(x, x)
|
| 1924 |
+
|
| 1925 |
+
"""
|
| 1926 |
+
if hints.get('deep', True):
|
| 1927 |
+
terms = [term.doit(**hints) if isinstance(term, Basic) else term
|
| 1928 |
+
for term in self.args]
|
| 1929 |
+
return self.func(*terms)
|
| 1930 |
+
else:
|
| 1931 |
+
return self
|
| 1932 |
+
|
| 1933 |
+
def simplify(self, **kwargs):
|
| 1934 |
+
"""See the simplify function in sympy.simplify"""
|
| 1935 |
+
from sympy.simplify.simplify import simplify
|
| 1936 |
+
return simplify(self, **kwargs)
|
| 1937 |
+
|
| 1938 |
+
def refine(self, assumption=True):
|
| 1939 |
+
"""See the refine function in sympy.assumptions"""
|
| 1940 |
+
from sympy.assumptions.refine import refine
|
| 1941 |
+
return refine(self, assumption)
|
| 1942 |
+
|
| 1943 |
+
def _eval_derivative_n_times(self, s, n):
|
| 1944 |
+
# This is the default evaluator for derivatives (as called by `diff`
|
| 1945 |
+
# and `Derivative`), it will attempt a loop to derive the expression
|
| 1946 |
+
# `n` times by calling the corresponding `_eval_derivative` method,
|
| 1947 |
+
# while leaving the derivative unevaluated if `n` is symbolic. This
|
| 1948 |
+
# method should be overridden if the object has a closed form for its
|
| 1949 |
+
# symbolic n-th derivative.
|
| 1950 |
+
from .numbers import Integer
|
| 1951 |
+
if isinstance(n, (int, Integer)):
|
| 1952 |
+
obj = self
|
| 1953 |
+
for i in range(n):
|
| 1954 |
+
obj2 = obj._eval_derivative(s)
|
| 1955 |
+
if obj == obj2 or obj2 is None:
|
| 1956 |
+
break
|
| 1957 |
+
obj = obj2
|
| 1958 |
+
return obj2
|
| 1959 |
+
else:
|
| 1960 |
+
return None
|
| 1961 |
+
|
| 1962 |
+
def rewrite(self, *args, deep=True, **hints):
|
| 1963 |
+
"""
|
| 1964 |
+
Rewrite *self* using a defined rule.
|
| 1965 |
+
|
| 1966 |
+
Rewriting transforms an expression to another, which is mathematically
|
| 1967 |
+
equivalent but structurally different. For example you can rewrite
|
| 1968 |
+
trigonometric functions as complex exponentials or combinatorial
|
| 1969 |
+
functions as gamma function.
|
| 1970 |
+
|
| 1971 |
+
This method takes a *pattern* and a *rule* as positional arguments.
|
| 1972 |
+
*pattern* is optional parameter which defines the types of expressions
|
| 1973 |
+
that will be transformed. If it is not passed, all possible expressions
|
| 1974 |
+
will be rewritten. *rule* defines how the expression will be rewritten.
|
| 1975 |
+
|
| 1976 |
+
Parameters
|
| 1977 |
+
==========
|
| 1978 |
+
|
| 1979 |
+
args : Expr
|
| 1980 |
+
A *rule*, or *pattern* and *rule*.
|
| 1981 |
+
- *pattern* is a type or an iterable of types.
|
| 1982 |
+
- *rule* can be any object.
|
| 1983 |
+
|
| 1984 |
+
deep : bool, optional
|
| 1985 |
+
If ``True``, subexpressions are recursively transformed. Default is
|
| 1986 |
+
``True``.
|
| 1987 |
+
|
| 1988 |
+
Examples
|
| 1989 |
+
========
|
| 1990 |
+
|
| 1991 |
+
If *pattern* is unspecified, all possible expressions are transformed.
|
| 1992 |
+
|
| 1993 |
+
>>> from sympy import cos, sin, exp, I
|
| 1994 |
+
>>> from sympy.abc import x
|
| 1995 |
+
>>> expr = cos(x) + I*sin(x)
|
| 1996 |
+
>>> expr.rewrite(exp)
|
| 1997 |
+
exp(I*x)
|
| 1998 |
+
|
| 1999 |
+
Pattern can be a type or an iterable of types.
|
| 2000 |
+
|
| 2001 |
+
>>> expr.rewrite(sin, exp)
|
| 2002 |
+
exp(I*x)/2 + cos(x) - exp(-I*x)/2
|
| 2003 |
+
>>> expr.rewrite([cos,], exp)
|
| 2004 |
+
exp(I*x)/2 + I*sin(x) + exp(-I*x)/2
|
| 2005 |
+
>>> expr.rewrite([cos, sin], exp)
|
| 2006 |
+
exp(I*x)
|
| 2007 |
+
|
| 2008 |
+
Rewriting behavior can be implemented by defining ``_eval_rewrite()``
|
| 2009 |
+
method.
|
| 2010 |
+
|
| 2011 |
+
>>> from sympy import Expr, sqrt, pi
|
| 2012 |
+
>>> class MySin(Expr):
|
| 2013 |
+
... def _eval_rewrite(self, rule, args, **hints):
|
| 2014 |
+
... x, = args
|
| 2015 |
+
... if rule == cos:
|
| 2016 |
+
... return cos(pi/2 - x, evaluate=False)
|
| 2017 |
+
... if rule == sqrt:
|
| 2018 |
+
... return sqrt(1 - cos(x)**2)
|
| 2019 |
+
>>> MySin(MySin(x)).rewrite(cos)
|
| 2020 |
+
cos(-cos(-x + pi/2) + pi/2)
|
| 2021 |
+
>>> MySin(x).rewrite(sqrt)
|
| 2022 |
+
sqrt(1 - cos(x)**2)
|
| 2023 |
+
|
| 2024 |
+
Defining ``_eval_rewrite_as_[...]()`` method is supported for backwards
|
| 2025 |
+
compatibility reason. This may be removed in the future and using it is
|
| 2026 |
+
discouraged.
|
| 2027 |
+
|
| 2028 |
+
>>> class MySin(Expr):
|
| 2029 |
+
... def _eval_rewrite_as_cos(self, *args, **hints):
|
| 2030 |
+
... x, = args
|
| 2031 |
+
... return cos(pi/2 - x, evaluate=False)
|
| 2032 |
+
>>> MySin(x).rewrite(cos)
|
| 2033 |
+
cos(-x + pi/2)
|
| 2034 |
+
|
| 2035 |
+
"""
|
| 2036 |
+
if not args:
|
| 2037 |
+
return self
|
| 2038 |
+
|
| 2039 |
+
hints.update(deep=deep)
|
| 2040 |
+
|
| 2041 |
+
pattern = args[:-1]
|
| 2042 |
+
rule = args[-1]
|
| 2043 |
+
|
| 2044 |
+
# support old design by _eval_rewrite_as_[...] method
|
| 2045 |
+
if isinstance(rule, str):
|
| 2046 |
+
method = "_eval_rewrite_as_%s" % rule
|
| 2047 |
+
elif hasattr(rule, "__name__"):
|
| 2048 |
+
# rule is class or function
|
| 2049 |
+
clsname = rule.__name__
|
| 2050 |
+
method = "_eval_rewrite_as_%s" % clsname
|
| 2051 |
+
else:
|
| 2052 |
+
# rule is instance
|
| 2053 |
+
clsname = rule.__class__.__name__
|
| 2054 |
+
method = "_eval_rewrite_as_%s" % clsname
|
| 2055 |
+
|
| 2056 |
+
if pattern:
|
| 2057 |
+
if iterable(pattern[0]):
|
| 2058 |
+
pattern = pattern[0]
|
| 2059 |
+
pattern = tuple(p for p in pattern if self.has(p))
|
| 2060 |
+
if not pattern:
|
| 2061 |
+
return self
|
| 2062 |
+
# hereafter, empty pattern is interpreted as all pattern.
|
| 2063 |
+
|
| 2064 |
+
return self._rewrite(pattern, rule, method, **hints)
|
| 2065 |
+
|
| 2066 |
+
def _rewrite(self, pattern, rule, method, **hints):
|
| 2067 |
+
deep = hints.pop('deep', True)
|
| 2068 |
+
if deep:
|
| 2069 |
+
args = [a._rewrite(pattern, rule, method, **hints)
|
| 2070 |
+
for a in self.args]
|
| 2071 |
+
else:
|
| 2072 |
+
args = self.args
|
| 2073 |
+
if not pattern or any(isinstance(self, p) for p in pattern):
|
| 2074 |
+
meth = getattr(self, method, None)
|
| 2075 |
+
if meth is not None:
|
| 2076 |
+
rewritten = meth(*args, **hints)
|
| 2077 |
+
else:
|
| 2078 |
+
rewritten = self._eval_rewrite(rule, args, **hints)
|
| 2079 |
+
if rewritten is not None:
|
| 2080 |
+
return rewritten
|
| 2081 |
+
if not args:
|
| 2082 |
+
return self
|
| 2083 |
+
return self.func(*args)
|
| 2084 |
+
|
| 2085 |
+
def _eval_rewrite(self, rule, args, **hints):
|
| 2086 |
+
return None
|
| 2087 |
+
|
| 2088 |
+
_constructor_postprocessor_mapping = {} # type: ignore
|
| 2089 |
+
|
| 2090 |
+
@classmethod
|
| 2091 |
+
def _exec_constructor_postprocessors(cls, obj):
|
| 2092 |
+
# WARNING: This API is experimental.
|
| 2093 |
+
|
| 2094 |
+
# This is an experimental API that introduces constructor
|
| 2095 |
+
# postprosessors for SymPy Core elements. If an argument of a SymPy
|
| 2096 |
+
# expression has a `_constructor_postprocessor_mapping` attribute, it will
|
| 2097 |
+
# be interpreted as a dictionary containing lists of postprocessing
|
| 2098 |
+
# functions for matching expression node names.
|
| 2099 |
+
|
| 2100 |
+
clsname = obj.__class__.__name__
|
| 2101 |
+
postprocessors = defaultdict(list)
|
| 2102 |
+
for i in obj.args:
|
| 2103 |
+
try:
|
| 2104 |
+
postprocessor_mappings = (
|
| 2105 |
+
Basic._constructor_postprocessor_mapping[cls].items()
|
| 2106 |
+
for cls in type(i).mro()
|
| 2107 |
+
if cls in Basic._constructor_postprocessor_mapping
|
| 2108 |
+
)
|
| 2109 |
+
for k, v in chain.from_iterable(postprocessor_mappings):
|
| 2110 |
+
postprocessors[k].extend([j for j in v if j not in postprocessors[k]])
|
| 2111 |
+
except TypeError:
|
| 2112 |
+
pass
|
| 2113 |
+
|
| 2114 |
+
for f in postprocessors.get(clsname, []):
|
| 2115 |
+
obj = f(obj)
|
| 2116 |
+
|
| 2117 |
+
return obj
|
| 2118 |
+
|
| 2119 |
+
def _sage_(self):
|
| 2120 |
+
"""
|
| 2121 |
+
Convert *self* to a symbolic expression of SageMath.
|
| 2122 |
+
|
| 2123 |
+
This version of the method is merely a placeholder.
|
| 2124 |
+
"""
|
| 2125 |
+
old_method = self._sage_
|
| 2126 |
+
from sage.interfaces.sympy import sympy_init
|
| 2127 |
+
sympy_init() # may monkey-patch _sage_ method into self's class or superclasses
|
| 2128 |
+
if old_method == self._sage_:
|
| 2129 |
+
raise NotImplementedError('conversion to SageMath is not implemented')
|
| 2130 |
+
else:
|
| 2131 |
+
# call the freshly monkey-patched method
|
| 2132 |
+
return self._sage_()
|
| 2133 |
+
|
| 2134 |
+
def could_extract_minus_sign(self):
|
| 2135 |
+
return False # see Expr.could_extract_minus_sign
|
| 2136 |
+
|
| 2137 |
+
def is_same(a, b, approx=None):
|
| 2138 |
+
"""Return True if a and b are structurally the same, else False.
|
| 2139 |
+
If `approx` is supplied, it will be used to test whether two
|
| 2140 |
+
numbers are the same or not. By default, only numbers of the
|
| 2141 |
+
same type will compare equal, so S.Half != Float(0.5).
|
| 2142 |
+
|
| 2143 |
+
Examples
|
| 2144 |
+
========
|
| 2145 |
+
|
| 2146 |
+
In SymPy (unlike Python) two numbers do not compare the same if they are
|
| 2147 |
+
not of the same type:
|
| 2148 |
+
|
| 2149 |
+
>>> from sympy import S
|
| 2150 |
+
>>> 2.0 == S(2)
|
| 2151 |
+
False
|
| 2152 |
+
>>> 0.5 == S.Half
|
| 2153 |
+
False
|
| 2154 |
+
|
| 2155 |
+
By supplying a function with which to compare two numbers, such
|
| 2156 |
+
differences can be ignored. e.g. `equal_valued` will return True
|
| 2157 |
+
for decimal numbers having a denominator that is a power of 2,
|
| 2158 |
+
regardless of precision.
|
| 2159 |
+
|
| 2160 |
+
>>> from sympy import Float
|
| 2161 |
+
>>> from sympy.core.numbers import equal_valued
|
| 2162 |
+
>>> (S.Half/4).is_same(Float(0.125, 1), equal_valued)
|
| 2163 |
+
True
|
| 2164 |
+
>>> Float(1, 2).is_same(Float(1, 10), equal_valued)
|
| 2165 |
+
True
|
| 2166 |
+
|
| 2167 |
+
But decimals without a power of 2 denominator will compare
|
| 2168 |
+
as not being the same.
|
| 2169 |
+
|
| 2170 |
+
>>> Float(0.1, 9).is_same(Float(0.1, 10), equal_valued)
|
| 2171 |
+
False
|
| 2172 |
+
|
| 2173 |
+
But arbitrary differences can be ignored by supplying a function
|
| 2174 |
+
to test the equivalence of two numbers:
|
| 2175 |
+
|
| 2176 |
+
>>> import math
|
| 2177 |
+
>>> Float(0.1, 9).is_same(Float(0.1, 10), math.isclose)
|
| 2178 |
+
True
|
| 2179 |
+
|
| 2180 |
+
Other objects might compare the same even though types are not the
|
| 2181 |
+
same. This routine will only return True if two expressions are
|
| 2182 |
+
identical in terms of class types.
|
| 2183 |
+
|
| 2184 |
+
>>> from sympy import eye, Basic
|
| 2185 |
+
>>> eye(1) == S(eye(1)) # mutable vs immutable
|
| 2186 |
+
True
|
| 2187 |
+
>>> Basic.is_same(eye(1), S(eye(1)))
|
| 2188 |
+
False
|
| 2189 |
+
|
| 2190 |
+
"""
|
| 2191 |
+
from .numbers import Number
|
| 2192 |
+
from .traversal import postorder_traversal as pot
|
| 2193 |
+
for t in zip_longest(pot(a), pot(b)):
|
| 2194 |
+
if None in t:
|
| 2195 |
+
return False
|
| 2196 |
+
a, b = t
|
| 2197 |
+
if isinstance(a, Number):
|
| 2198 |
+
if not isinstance(b, Number):
|
| 2199 |
+
return False
|
| 2200 |
+
if approx:
|
| 2201 |
+
return approx(a, b)
|
| 2202 |
+
if not (a == b and a.__class__ == b.__class__):
|
| 2203 |
+
return False
|
| 2204 |
+
return True
|
| 2205 |
+
|
| 2206 |
+
_aresame = Basic.is_same # for sake of others importing this
|
| 2207 |
+
|
| 2208 |
+
# key used by Mul and Add to make canonical args
|
| 2209 |
+
_args_sortkey = cmp_to_key(Basic.compare)
|
| 2210 |
+
|
| 2211 |
+
# For all Basic subclasses _prepare_class_assumptions is called by
|
| 2212 |
+
# Basic.__init_subclass__ but that method is not called for Basic itself so we
|
| 2213 |
+
# call the function here instead.
|
| 2214 |
+
_prepare_class_assumptions(Basic)
|
| 2215 |
+
|
| 2216 |
+
|
| 2217 |
+
class Atom(Basic):
|
| 2218 |
+
"""
|
| 2219 |
+
A parent class for atomic things. An atom is an expression with no subexpressions.
|
| 2220 |
+
|
| 2221 |
+
Examples
|
| 2222 |
+
========
|
| 2223 |
+
|
| 2224 |
+
Symbol, Number, Rational, Integer, ...
|
| 2225 |
+
But not: Add, Mul, Pow, ...
|
| 2226 |
+
"""
|
| 2227 |
+
|
| 2228 |
+
is_Atom = True
|
| 2229 |
+
|
| 2230 |
+
__slots__ = ()
|
| 2231 |
+
|
| 2232 |
+
def matches(self, expr, repl_dict=None, old=False):
|
| 2233 |
+
if self == expr:
|
| 2234 |
+
if repl_dict is None:
|
| 2235 |
+
return {}
|
| 2236 |
+
return repl_dict.copy()
|
| 2237 |
+
|
| 2238 |
+
def xreplace(self, rule, hack2=False):
|
| 2239 |
+
return rule.get(self, self)
|
| 2240 |
+
|
| 2241 |
+
def doit(self, **hints):
|
| 2242 |
+
return self
|
| 2243 |
+
|
| 2244 |
+
@classmethod
|
| 2245 |
+
def class_key(cls):
|
| 2246 |
+
return 2, 0, cls.__name__
|
| 2247 |
+
|
| 2248 |
+
@cacheit
|
| 2249 |
+
def sort_key(self, order=None):
|
| 2250 |
+
return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One
|
| 2251 |
+
|
| 2252 |
+
def _eval_simplify(self, **kwargs):
|
| 2253 |
+
return self
|
| 2254 |
+
|
| 2255 |
+
@property
|
| 2256 |
+
def _sorted_args(self):
|
| 2257 |
+
# this is here as a safeguard against accidentally using _sorted_args
|
| 2258 |
+
# on Atoms -- they cannot be rebuilt as atom.func(*atom._sorted_args)
|
| 2259 |
+
# since there are no args. So the calling routine should be checking
|
| 2260 |
+
# to see that this property is not called for Atoms.
|
| 2261 |
+
raise AttributeError('Atoms have no args. It might be necessary'
|
| 2262 |
+
' to make a check for Atoms in the calling code.')
|
| 2263 |
+
|
| 2264 |
+
|
| 2265 |
+
def _atomic(e, recursive=False):
|
| 2266 |
+
"""Return atom-like quantities as far as substitution is
|
| 2267 |
+
concerned: Derivatives, Functions and Symbols. Do not
|
| 2268 |
+
return any 'atoms' that are inside such quantities unless
|
| 2269 |
+
they also appear outside, too, unless `recursive` is True.
|
| 2270 |
+
|
| 2271 |
+
Examples
|
| 2272 |
+
========
|
| 2273 |
+
|
| 2274 |
+
>>> from sympy import Derivative, Function, cos
|
| 2275 |
+
>>> from sympy.abc import x, y
|
| 2276 |
+
>>> from sympy.core.basic import _atomic
|
| 2277 |
+
>>> f = Function('f')
|
| 2278 |
+
>>> _atomic(x + y)
|
| 2279 |
+
{x, y}
|
| 2280 |
+
>>> _atomic(x + f(y))
|
| 2281 |
+
{x, f(y)}
|
| 2282 |
+
>>> _atomic(Derivative(f(x), x) + cos(x) + y)
|
| 2283 |
+
{y, cos(x), Derivative(f(x), x)}
|
| 2284 |
+
|
| 2285 |
+
"""
|
| 2286 |
+
pot = _preorder_traversal(e)
|
| 2287 |
+
seen = set()
|
| 2288 |
+
if isinstance(e, Basic):
|
| 2289 |
+
free = getattr(e, "free_symbols", None)
|
| 2290 |
+
if free is None:
|
| 2291 |
+
return {e}
|
| 2292 |
+
else:
|
| 2293 |
+
return set()
|
| 2294 |
+
from .symbol import Symbol
|
| 2295 |
+
from .function import Derivative, Function
|
| 2296 |
+
atoms = set()
|
| 2297 |
+
for p in pot:
|
| 2298 |
+
if p in seen:
|
| 2299 |
+
pot.skip()
|
| 2300 |
+
continue
|
| 2301 |
+
seen.add(p)
|
| 2302 |
+
if isinstance(p, Symbol) and p in free:
|
| 2303 |
+
atoms.add(p)
|
| 2304 |
+
elif isinstance(p, (Derivative, Function)):
|
| 2305 |
+
if not recursive:
|
| 2306 |
+
pot.skip()
|
| 2307 |
+
atoms.add(p)
|
| 2308 |
+
return atoms
|
| 2309 |
+
|
| 2310 |
+
|
| 2311 |
+
def _make_find_query(query):
|
| 2312 |
+
"""Convert the argument of Basic.find() into a callable"""
|
| 2313 |
+
try:
|
| 2314 |
+
query = _sympify(query)
|
| 2315 |
+
except SympifyError:
|
| 2316 |
+
pass
|
| 2317 |
+
if isinstance(query, type):
|
| 2318 |
+
return lambda expr: isinstance(expr, query)
|
| 2319 |
+
elif isinstance(query, Basic):
|
| 2320 |
+
return lambda expr: expr.match(query) is not None
|
| 2321 |
+
return query
|
| 2322 |
+
|
| 2323 |
+
# Delayed to avoid cyclic import
|
| 2324 |
+
from .singleton import S
|
| 2325 |
+
from .traversal import (preorder_traversal as _preorder_traversal,
|
| 2326 |
+
iterargs, iterfreeargs)
|
| 2327 |
+
|
| 2328 |
+
preorder_traversal = deprecated(
|
| 2329 |
+
"""
|
| 2330 |
+
Using preorder_traversal from the sympy.core.basic submodule is
|
| 2331 |
+
deprecated.
|
| 2332 |
+
|
| 2333 |
+
Instead, use preorder_traversal from the top-level sympy namespace, like
|
| 2334 |
+
|
| 2335 |
+
sympy.preorder_traversal
|
| 2336 |
+
""",
|
| 2337 |
+
deprecated_since_version="1.10",
|
| 2338 |
+
active_deprecations_target="deprecated-traversal-functions-moved",
|
| 2339 |
+
)(_preorder_traversal)
|
lib/python3.12/site-packages/sympy/core/cache.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
""" Caching facility for SymPy """
|
| 2 |
+
from importlib import import_module
|
| 3 |
+
from typing import Callable
|
| 4 |
+
|
| 5 |
+
class _cache(list):
|
| 6 |
+
""" List of cached functions """
|
| 7 |
+
|
| 8 |
+
def print_cache(self):
|
| 9 |
+
"""print cache info"""
|
| 10 |
+
|
| 11 |
+
for item in self:
|
| 12 |
+
name = item.__name__
|
| 13 |
+
myfunc = item
|
| 14 |
+
while hasattr(myfunc, '__wrapped__'):
|
| 15 |
+
if hasattr(myfunc, 'cache_info'):
|
| 16 |
+
info = myfunc.cache_info()
|
| 17 |
+
break
|
| 18 |
+
else:
|
| 19 |
+
myfunc = myfunc.__wrapped__
|
| 20 |
+
else:
|
| 21 |
+
info = None
|
| 22 |
+
|
| 23 |
+
print(name, info)
|
| 24 |
+
|
| 25 |
+
def clear_cache(self):
|
| 26 |
+
"""clear cache content"""
|
| 27 |
+
for item in self:
|
| 28 |
+
myfunc = item
|
| 29 |
+
while hasattr(myfunc, '__wrapped__'):
|
| 30 |
+
if hasattr(myfunc, 'cache_clear'):
|
| 31 |
+
myfunc.cache_clear()
|
| 32 |
+
break
|
| 33 |
+
else:
|
| 34 |
+
myfunc = myfunc.__wrapped__
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
# global cache registry:
|
| 38 |
+
CACHE = _cache()
|
| 39 |
+
# make clear and print methods available
|
| 40 |
+
print_cache = CACHE.print_cache
|
| 41 |
+
clear_cache = CACHE.clear_cache
|
| 42 |
+
|
| 43 |
+
from functools import lru_cache, wraps
|
| 44 |
+
|
| 45 |
+
def __cacheit(maxsize):
|
| 46 |
+
"""caching decorator.
|
| 47 |
+
|
| 48 |
+
important: the result of cached function must be *immutable*
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
Examples
|
| 52 |
+
========
|
| 53 |
+
|
| 54 |
+
>>> from sympy import cacheit
|
| 55 |
+
>>> @cacheit
|
| 56 |
+
... def f(a, b):
|
| 57 |
+
... return a+b
|
| 58 |
+
|
| 59 |
+
>>> @cacheit
|
| 60 |
+
... def f(a, b): # noqa: F811
|
| 61 |
+
... return [a, b] # <-- WRONG, returns mutable object
|
| 62 |
+
|
| 63 |
+
to force cacheit to check returned results mutability and consistency,
|
| 64 |
+
set environment variable SYMPY_USE_CACHE to 'debug'
|
| 65 |
+
"""
|
| 66 |
+
def func_wrapper(func):
|
| 67 |
+
cfunc = lru_cache(maxsize, typed=True)(func)
|
| 68 |
+
|
| 69 |
+
@wraps(func)
|
| 70 |
+
def wrapper(*args, **kwargs):
|
| 71 |
+
try:
|
| 72 |
+
retval = cfunc(*args, **kwargs)
|
| 73 |
+
except TypeError as e:
|
| 74 |
+
if not e.args or not e.args[0].startswith('unhashable type:'):
|
| 75 |
+
raise
|
| 76 |
+
retval = func(*args, **kwargs)
|
| 77 |
+
return retval
|
| 78 |
+
|
| 79 |
+
wrapper.cache_info = cfunc.cache_info
|
| 80 |
+
wrapper.cache_clear = cfunc.cache_clear
|
| 81 |
+
|
| 82 |
+
CACHE.append(wrapper)
|
| 83 |
+
return wrapper
|
| 84 |
+
|
| 85 |
+
return func_wrapper
|
| 86 |
+
########################################
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def __cacheit_nocache(func):
|
| 90 |
+
return func
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def __cacheit_debug(maxsize):
|
| 94 |
+
"""cacheit + code to check cache consistency"""
|
| 95 |
+
def func_wrapper(func):
|
| 96 |
+
cfunc = __cacheit(maxsize)(func)
|
| 97 |
+
|
| 98 |
+
@wraps(func)
|
| 99 |
+
def wrapper(*args, **kw_args):
|
| 100 |
+
# always call function itself and compare it with cached version
|
| 101 |
+
r1 = func(*args, **kw_args)
|
| 102 |
+
r2 = cfunc(*args, **kw_args)
|
| 103 |
+
|
| 104 |
+
# try to see if the result is immutable
|
| 105 |
+
#
|
| 106 |
+
# this works because:
|
| 107 |
+
#
|
| 108 |
+
# hash([1,2,3]) -> raise TypeError
|
| 109 |
+
# hash({'a':1, 'b':2}) -> raise TypeError
|
| 110 |
+
# hash((1,[2,3])) -> raise TypeError
|
| 111 |
+
#
|
| 112 |
+
# hash((1,2,3)) -> just computes the hash
|
| 113 |
+
hash(r1), hash(r2)
|
| 114 |
+
|
| 115 |
+
# also see if returned values are the same
|
| 116 |
+
if r1 != r2:
|
| 117 |
+
raise RuntimeError("Returned values are not the same")
|
| 118 |
+
return r1
|
| 119 |
+
return wrapper
|
| 120 |
+
return func_wrapper
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _getenv(key, default=None):
|
| 124 |
+
from os import getenv
|
| 125 |
+
return getenv(key, default)
|
| 126 |
+
|
| 127 |
+
# SYMPY_USE_CACHE=yes/no/debug
|
| 128 |
+
USE_CACHE = _getenv('SYMPY_USE_CACHE', 'yes').lower()
|
| 129 |
+
# SYMPY_CACHE_SIZE=some_integer/None
|
| 130 |
+
# special cases :
|
| 131 |
+
# SYMPY_CACHE_SIZE=0 -> No caching
|
| 132 |
+
# SYMPY_CACHE_SIZE=None -> Unbounded caching
|
| 133 |
+
scs = _getenv('SYMPY_CACHE_SIZE', '1000')
|
| 134 |
+
if scs.lower() == 'none':
|
| 135 |
+
SYMPY_CACHE_SIZE = None
|
| 136 |
+
else:
|
| 137 |
+
try:
|
| 138 |
+
SYMPY_CACHE_SIZE = int(scs)
|
| 139 |
+
except ValueError:
|
| 140 |
+
raise RuntimeError(
|
| 141 |
+
'SYMPY_CACHE_SIZE must be a valid integer or None. ' + \
|
| 142 |
+
'Got: %s' % SYMPY_CACHE_SIZE)
|
| 143 |
+
|
| 144 |
+
if USE_CACHE == 'no':
|
| 145 |
+
cacheit = __cacheit_nocache
|
| 146 |
+
elif USE_CACHE == 'yes':
|
| 147 |
+
cacheit = __cacheit(SYMPY_CACHE_SIZE)
|
| 148 |
+
elif USE_CACHE == 'debug':
|
| 149 |
+
cacheit = __cacheit_debug(SYMPY_CACHE_SIZE) # a lot slower
|
| 150 |
+
else:
|
| 151 |
+
raise RuntimeError(
|
| 152 |
+
'unrecognized value for SYMPY_USE_CACHE: %s' % USE_CACHE)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def cached_property(func):
|
| 156 |
+
'''Decorator to cache property method'''
|
| 157 |
+
attrname = '__' + func.__name__
|
| 158 |
+
_cached_property_sentinel = object()
|
| 159 |
+
def propfunc(self):
|
| 160 |
+
val = getattr(self, attrname, _cached_property_sentinel)
|
| 161 |
+
if val is _cached_property_sentinel:
|
| 162 |
+
val = func(self)
|
| 163 |
+
setattr(self, attrname, val)
|
| 164 |
+
return val
|
| 165 |
+
return property(propfunc)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def lazy_function(module : str, name : str) -> Callable:
|
| 169 |
+
"""Create a lazy proxy for a function in a module.
|
| 170 |
+
|
| 171 |
+
The module containing the function is not imported until the function is used.
|
| 172 |
+
|
| 173 |
+
"""
|
| 174 |
+
func = None
|
| 175 |
+
|
| 176 |
+
def _get_function():
|
| 177 |
+
nonlocal func
|
| 178 |
+
if func is None:
|
| 179 |
+
func = getattr(import_module(module), name)
|
| 180 |
+
return func
|
| 181 |
+
|
| 182 |
+
# The metaclass is needed so that help() shows the docstring
|
| 183 |
+
class LazyFunctionMeta(type):
|
| 184 |
+
@property
|
| 185 |
+
def __doc__(self):
|
| 186 |
+
docstring = _get_function().__doc__
|
| 187 |
+
docstring += f"\n\nNote: this is a {self.__class__.__name__} wrapper of '{module}.{name}'"
|
| 188 |
+
return docstring
|
| 189 |
+
|
| 190 |
+
class LazyFunction(metaclass=LazyFunctionMeta):
|
| 191 |
+
def __call__(self, *args, **kwargs):
|
| 192 |
+
# inline get of function for performance gh-23832
|
| 193 |
+
nonlocal func
|
| 194 |
+
if func is None:
|
| 195 |
+
func = getattr(import_module(module), name)
|
| 196 |
+
return func(*args, **kwargs)
|
| 197 |
+
|
| 198 |
+
@property
|
| 199 |
+
def __doc__(self):
|
| 200 |
+
docstring = _get_function().__doc__
|
| 201 |
+
docstring += f"\n\nNote: this is a {self.__class__.__name__} wrapper of '{module}.{name}'"
|
| 202 |
+
return docstring
|
| 203 |
+
|
| 204 |
+
def __str__(self):
|
| 205 |
+
return _get_function().__str__()
|
| 206 |
+
|
| 207 |
+
def __repr__(self):
|
| 208 |
+
return f"<{__class__.__name__} object at 0x{id(self):x}>: wrapping '{module}.{name}'"
|
| 209 |
+
|
| 210 |
+
return LazyFunction()
|
lib/python3.12/site-packages/sympy/core/compatibility.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
.. deprecated:: 1.10
|
| 3 |
+
|
| 4 |
+
``sympy.core.compatibility`` is deprecated. See
|
| 5 |
+
:ref:`sympy-core-compatibility`.
|
| 6 |
+
|
| 7 |
+
Reimplementations of constructs introduced in later versions of Python than
|
| 8 |
+
we support. Also some functions that are needed SymPy-wide and are located
|
| 9 |
+
here for easy import.
|
| 10 |
+
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
from sympy.utilities.exceptions import sympy_deprecation_warning
|
| 15 |
+
|
| 16 |
+
sympy_deprecation_warning("""
|
| 17 |
+
The sympy.core.compatibility submodule is deprecated.
|
| 18 |
+
|
| 19 |
+
This module was only ever intended for internal use. Some of the functions
|
| 20 |
+
that were in this module are available from the top-level SymPy namespace,
|
| 21 |
+
i.e.,
|
| 22 |
+
|
| 23 |
+
from sympy import ordered, default_sort_key
|
| 24 |
+
|
| 25 |
+
The remaining were only intended for internal SymPy use and should not be used
|
| 26 |
+
by user code.
|
| 27 |
+
""",
|
| 28 |
+
deprecated_since_version="1.10",
|
| 29 |
+
active_deprecations_target="deprecated-sympy-core-compatibility",
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
from .sorting import ordered, _nodes, default_sort_key # noqa:F401
|
| 34 |
+
from sympy.utilities.misc import as_int as _as_int # noqa:F401
|
| 35 |
+
from sympy.utilities.iterables import iterable, is_sequence, NotIterable # noqa:F401
|
lib/python3.12/site-packages/sympy/core/containers.py
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Module for SymPy containers
|
| 2 |
+
|
| 3 |
+
(SymPy objects that store other SymPy objects)
|
| 4 |
+
|
| 5 |
+
The containers implemented in this module are subclassed to Basic.
|
| 6 |
+
They are supposed to work seamlessly within the SymPy framework.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
from collections import OrderedDict
|
| 10 |
+
from collections.abc import MutableSet
|
| 11 |
+
from typing import Any, Callable
|
| 12 |
+
|
| 13 |
+
from .basic import Basic
|
| 14 |
+
from .sorting import default_sort_key, ordered
|
| 15 |
+
from .sympify import _sympify, sympify, _sympy_converter, SympifyError
|
| 16 |
+
from sympy.core.kind import Kind
|
| 17 |
+
from sympy.utilities.iterables import iterable
|
| 18 |
+
from sympy.utilities.misc import as_int
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class Tuple(Basic):
|
| 22 |
+
"""
|
| 23 |
+
Wrapper around the builtin tuple object.
|
| 24 |
+
|
| 25 |
+
Explanation
|
| 26 |
+
===========
|
| 27 |
+
|
| 28 |
+
The Tuple is a subclass of Basic, so that it works well in the
|
| 29 |
+
SymPy framework. The wrapped tuple is available as self.args, but
|
| 30 |
+
you can also access elements or slices with [:] syntax.
|
| 31 |
+
|
| 32 |
+
Parameters
|
| 33 |
+
==========
|
| 34 |
+
|
| 35 |
+
sympify : bool
|
| 36 |
+
If ``False``, ``sympify`` is not called on ``args``. This
|
| 37 |
+
can be used for speedups for very large tuples where the
|
| 38 |
+
elements are known to already be SymPy objects.
|
| 39 |
+
|
| 40 |
+
Examples
|
| 41 |
+
========
|
| 42 |
+
|
| 43 |
+
>>> from sympy import Tuple, symbols
|
| 44 |
+
>>> a, b, c, d = symbols('a b c d')
|
| 45 |
+
>>> Tuple(a, b, c)[1:]
|
| 46 |
+
(b, c)
|
| 47 |
+
>>> Tuple(a, b, c).subs(a, d)
|
| 48 |
+
(d, b, c)
|
| 49 |
+
|
| 50 |
+
"""
|
| 51 |
+
|
| 52 |
+
def __new__(cls, *args, **kwargs):
|
| 53 |
+
if kwargs.get('sympify', True):
|
| 54 |
+
args = (sympify(arg) for arg in args)
|
| 55 |
+
obj = Basic.__new__(cls, *args)
|
| 56 |
+
return obj
|
| 57 |
+
|
| 58 |
+
def __getitem__(self, i):
|
| 59 |
+
if isinstance(i, slice):
|
| 60 |
+
indices = i.indices(len(self))
|
| 61 |
+
return Tuple(*(self.args[j] for j in range(*indices)))
|
| 62 |
+
return self.args[i]
|
| 63 |
+
|
| 64 |
+
def __len__(self):
|
| 65 |
+
return len(self.args)
|
| 66 |
+
|
| 67 |
+
def __contains__(self, item):
|
| 68 |
+
return item in self.args
|
| 69 |
+
|
| 70 |
+
def __iter__(self):
|
| 71 |
+
return iter(self.args)
|
| 72 |
+
|
| 73 |
+
def __add__(self, other):
|
| 74 |
+
if isinstance(other, Tuple):
|
| 75 |
+
return Tuple(*(self.args + other.args))
|
| 76 |
+
elif isinstance(other, tuple):
|
| 77 |
+
return Tuple(*(self.args + other))
|
| 78 |
+
else:
|
| 79 |
+
return NotImplemented
|
| 80 |
+
|
| 81 |
+
def __radd__(self, other):
|
| 82 |
+
if isinstance(other, Tuple):
|
| 83 |
+
return Tuple(*(other.args + self.args))
|
| 84 |
+
elif isinstance(other, tuple):
|
| 85 |
+
return Tuple(*(other + self.args))
|
| 86 |
+
else:
|
| 87 |
+
return NotImplemented
|
| 88 |
+
|
| 89 |
+
def __mul__(self, other):
|
| 90 |
+
try:
|
| 91 |
+
n = as_int(other)
|
| 92 |
+
except ValueError:
|
| 93 |
+
raise TypeError("Can't multiply sequence by non-integer of type '%s'" % type(other))
|
| 94 |
+
return self.func(*(self.args*n))
|
| 95 |
+
|
| 96 |
+
__rmul__ = __mul__
|
| 97 |
+
|
| 98 |
+
def __eq__(self, other):
|
| 99 |
+
if isinstance(other, Basic):
|
| 100 |
+
return super().__eq__(other)
|
| 101 |
+
return self.args == other
|
| 102 |
+
|
| 103 |
+
def __ne__(self, other):
|
| 104 |
+
if isinstance(other, Basic):
|
| 105 |
+
return super().__ne__(other)
|
| 106 |
+
return self.args != other
|
| 107 |
+
|
| 108 |
+
def __hash__(self):
|
| 109 |
+
return hash(self.args)
|
| 110 |
+
|
| 111 |
+
def _to_mpmath(self, prec):
|
| 112 |
+
return tuple(a._to_mpmath(prec) for a in self.args)
|
| 113 |
+
|
| 114 |
+
def __lt__(self, other):
|
| 115 |
+
return _sympify(self.args < other.args)
|
| 116 |
+
|
| 117 |
+
def __le__(self, other):
|
| 118 |
+
return _sympify(self.args <= other.args)
|
| 119 |
+
|
| 120 |
+
# XXX: Basic defines count() as something different, so we can't
|
| 121 |
+
# redefine it here. Originally this lead to cse() test failure.
|
| 122 |
+
def tuple_count(self, value) -> int:
|
| 123 |
+
"""Return number of occurrences of value."""
|
| 124 |
+
return self.args.count(value)
|
| 125 |
+
|
| 126 |
+
def index(self, value, start=None, stop=None):
|
| 127 |
+
"""Searches and returns the first index of the value."""
|
| 128 |
+
# XXX: One would expect:
|
| 129 |
+
#
|
| 130 |
+
# return self.args.index(value, start, stop)
|
| 131 |
+
#
|
| 132 |
+
# here. Any trouble with that? Yes:
|
| 133 |
+
#
|
| 134 |
+
# >>> (1,).index(1, None, None)
|
| 135 |
+
# Traceback (most recent call last):
|
| 136 |
+
# File "<stdin>", line 1, in <module>
|
| 137 |
+
# TypeError: slice indices must be integers or None or have an __index__ method
|
| 138 |
+
#
|
| 139 |
+
# See: http://bugs.python.org/issue13340
|
| 140 |
+
|
| 141 |
+
if start is None and stop is None:
|
| 142 |
+
return self.args.index(value)
|
| 143 |
+
elif stop is None:
|
| 144 |
+
return self.args.index(value, start)
|
| 145 |
+
else:
|
| 146 |
+
return self.args.index(value, start, stop)
|
| 147 |
+
|
| 148 |
+
@property
|
| 149 |
+
def kind(self):
|
| 150 |
+
"""
|
| 151 |
+
The kind of a Tuple instance.
|
| 152 |
+
|
| 153 |
+
The kind of a Tuple is always of :class:`TupleKind` but
|
| 154 |
+
parametrised by the number of elements and the kind of each element.
|
| 155 |
+
|
| 156 |
+
Examples
|
| 157 |
+
========
|
| 158 |
+
|
| 159 |
+
>>> from sympy import Tuple, Matrix
|
| 160 |
+
>>> Tuple(1, 2).kind
|
| 161 |
+
TupleKind(NumberKind, NumberKind)
|
| 162 |
+
>>> Tuple(Matrix([1, 2]), 1).kind
|
| 163 |
+
TupleKind(MatrixKind(NumberKind), NumberKind)
|
| 164 |
+
>>> Tuple(1, 2).kind.element_kind
|
| 165 |
+
(NumberKind, NumberKind)
|
| 166 |
+
|
| 167 |
+
See Also
|
| 168 |
+
========
|
| 169 |
+
|
| 170 |
+
sympy.matrices.kind.MatrixKind
|
| 171 |
+
sympy.core.kind.NumberKind
|
| 172 |
+
"""
|
| 173 |
+
return TupleKind(*(i.kind for i in self.args))
|
| 174 |
+
|
| 175 |
+
_sympy_converter[tuple] = lambda tup: Tuple(*tup)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def tuple_wrapper(method):
|
| 182 |
+
"""
|
| 183 |
+
Decorator that converts any tuple in the function arguments into a Tuple.
|
| 184 |
+
|
| 185 |
+
Explanation
|
| 186 |
+
===========
|
| 187 |
+
|
| 188 |
+
The motivation for this is to provide simple user interfaces. The user can
|
| 189 |
+
call a function with regular tuples in the argument, and the wrapper will
|
| 190 |
+
convert them to Tuples before handing them to the function.
|
| 191 |
+
|
| 192 |
+
Explanation
|
| 193 |
+
===========
|
| 194 |
+
|
| 195 |
+
>>> from sympy.core.containers import tuple_wrapper
|
| 196 |
+
>>> def f(*args):
|
| 197 |
+
... return args
|
| 198 |
+
>>> g = tuple_wrapper(f)
|
| 199 |
+
|
| 200 |
+
The decorated function g sees only the Tuple argument:
|
| 201 |
+
|
| 202 |
+
>>> g(0, (1, 2), 3)
|
| 203 |
+
(0, (1, 2), 3)
|
| 204 |
+
|
| 205 |
+
"""
|
| 206 |
+
def wrap_tuples(*args, **kw_args):
|
| 207 |
+
newargs = []
|
| 208 |
+
for arg in args:
|
| 209 |
+
if isinstance(arg, tuple):
|
| 210 |
+
newargs.append(Tuple(*arg))
|
| 211 |
+
else:
|
| 212 |
+
newargs.append(arg)
|
| 213 |
+
return method(*newargs, **kw_args)
|
| 214 |
+
return wrap_tuples
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
class Dict(Basic):
|
| 218 |
+
"""
|
| 219 |
+
Wrapper around the builtin dict object.
|
| 220 |
+
|
| 221 |
+
Explanation
|
| 222 |
+
===========
|
| 223 |
+
|
| 224 |
+
The Dict is a subclass of Basic, so that it works well in the
|
| 225 |
+
SymPy framework. Because it is immutable, it may be included
|
| 226 |
+
in sets, but its values must all be given at instantiation and
|
| 227 |
+
cannot be changed afterwards. Otherwise it behaves identically
|
| 228 |
+
to the Python dict.
|
| 229 |
+
|
| 230 |
+
Examples
|
| 231 |
+
========
|
| 232 |
+
|
| 233 |
+
>>> from sympy import Dict, Symbol
|
| 234 |
+
|
| 235 |
+
>>> D = Dict({1: 'one', 2: 'two'})
|
| 236 |
+
>>> for key in D:
|
| 237 |
+
... if key == 1:
|
| 238 |
+
... print('%s %s' % (key, D[key]))
|
| 239 |
+
1 one
|
| 240 |
+
|
| 241 |
+
The args are sympified so the 1 and 2 are Integers and the values
|
| 242 |
+
are Symbols. Queries automatically sympify args so the following work:
|
| 243 |
+
|
| 244 |
+
>>> 1 in D
|
| 245 |
+
True
|
| 246 |
+
>>> D.has(Symbol('one')) # searches keys and values
|
| 247 |
+
True
|
| 248 |
+
>>> 'one' in D # not in the keys
|
| 249 |
+
False
|
| 250 |
+
>>> D[1]
|
| 251 |
+
one
|
| 252 |
+
|
| 253 |
+
"""
|
| 254 |
+
|
| 255 |
+
def __new__(cls, *args):
|
| 256 |
+
if len(args) == 1 and isinstance(args[0], (dict, Dict)):
|
| 257 |
+
items = [Tuple(k, v) for k, v in args[0].items()]
|
| 258 |
+
elif iterable(args) and all(len(arg) == 2 for arg in args):
|
| 259 |
+
items = [Tuple(k, v) for k, v in args]
|
| 260 |
+
else:
|
| 261 |
+
raise TypeError('Pass Dict args as Dict((k1, v1), ...) or Dict({k1: v1, ...})')
|
| 262 |
+
elements = frozenset(items)
|
| 263 |
+
obj = Basic.__new__(cls, *ordered(items))
|
| 264 |
+
obj.elements = elements
|
| 265 |
+
obj._dict = dict(items) # In case Tuple decides it wants to sympify
|
| 266 |
+
return obj
|
| 267 |
+
|
| 268 |
+
def __getitem__(self, key):
|
| 269 |
+
"""x.__getitem__(y) <==> x[y]"""
|
| 270 |
+
try:
|
| 271 |
+
key = _sympify(key)
|
| 272 |
+
except SympifyError:
|
| 273 |
+
raise KeyError(key)
|
| 274 |
+
|
| 275 |
+
return self._dict[key]
|
| 276 |
+
|
| 277 |
+
def __setitem__(self, key, value):
|
| 278 |
+
raise NotImplementedError("SymPy Dicts are Immutable")
|
| 279 |
+
|
| 280 |
+
def items(self):
|
| 281 |
+
'''Returns a set-like object providing a view on dict's items.
|
| 282 |
+
'''
|
| 283 |
+
return self._dict.items()
|
| 284 |
+
|
| 285 |
+
def keys(self):
|
| 286 |
+
'''Returns the list of the dict's keys.'''
|
| 287 |
+
return self._dict.keys()
|
| 288 |
+
|
| 289 |
+
def values(self):
|
| 290 |
+
'''Returns the list of the dict's values.'''
|
| 291 |
+
return self._dict.values()
|
| 292 |
+
|
| 293 |
+
def __iter__(self):
|
| 294 |
+
'''x.__iter__() <==> iter(x)'''
|
| 295 |
+
return iter(self._dict)
|
| 296 |
+
|
| 297 |
+
def __len__(self):
|
| 298 |
+
'''x.__len__() <==> len(x)'''
|
| 299 |
+
return self._dict.__len__()
|
| 300 |
+
|
| 301 |
+
def get(self, key, default=None):
|
| 302 |
+
'''Returns the value for key if the key is in the dictionary.'''
|
| 303 |
+
try:
|
| 304 |
+
key = _sympify(key)
|
| 305 |
+
except SympifyError:
|
| 306 |
+
return default
|
| 307 |
+
return self._dict.get(key, default)
|
| 308 |
+
|
| 309 |
+
def __contains__(self, key):
|
| 310 |
+
'''D.__contains__(k) -> True if D has a key k, else False'''
|
| 311 |
+
try:
|
| 312 |
+
key = _sympify(key)
|
| 313 |
+
except SympifyError:
|
| 314 |
+
return False
|
| 315 |
+
return key in self._dict
|
| 316 |
+
|
| 317 |
+
def __lt__(self, other):
|
| 318 |
+
return _sympify(self.args < other.args)
|
| 319 |
+
|
| 320 |
+
@property
|
| 321 |
+
def _sorted_args(self):
|
| 322 |
+
return tuple(sorted(self.args, key=default_sort_key))
|
| 323 |
+
|
| 324 |
+
def __eq__(self, other):
|
| 325 |
+
if isinstance(other, dict):
|
| 326 |
+
return self == Dict(other)
|
| 327 |
+
return super().__eq__(other)
|
| 328 |
+
|
| 329 |
+
__hash__ : Callable[[Basic], Any] = Basic.__hash__
|
| 330 |
+
|
| 331 |
+
# this handles dict, defaultdict, OrderedDict
|
| 332 |
+
_sympy_converter[dict] = lambda d: Dict(*d.items())
|
| 333 |
+
|
| 334 |
+
class OrderedSet(MutableSet):
|
| 335 |
+
def __init__(self, iterable=None):
|
| 336 |
+
if iterable:
|
| 337 |
+
self.map = OrderedDict((item, None) for item in iterable)
|
| 338 |
+
else:
|
| 339 |
+
self.map = OrderedDict()
|
| 340 |
+
|
| 341 |
+
def __len__(self):
|
| 342 |
+
return len(self.map)
|
| 343 |
+
|
| 344 |
+
def __contains__(self, key):
|
| 345 |
+
return key in self.map
|
| 346 |
+
|
| 347 |
+
def add(self, key):
|
| 348 |
+
self.map[key] = None
|
| 349 |
+
|
| 350 |
+
def discard(self, key):
|
| 351 |
+
self.map.pop(key)
|
| 352 |
+
|
| 353 |
+
def pop(self, last=True):
|
| 354 |
+
return self.map.popitem(last=last)[0]
|
| 355 |
+
|
| 356 |
+
def __iter__(self):
|
| 357 |
+
yield from self.map.keys()
|
| 358 |
+
|
| 359 |
+
def __repr__(self):
|
| 360 |
+
if not self.map:
|
| 361 |
+
return '%s()' % (self.__class__.__name__,)
|
| 362 |
+
return '%s(%r)' % (self.__class__.__name__, list(self.map.keys()))
|
| 363 |
+
|
| 364 |
+
def intersection(self, other):
|
| 365 |
+
return self.__class__([val for val in self if val in other])
|
| 366 |
+
|
| 367 |
+
def difference(self, other):
|
| 368 |
+
return self.__class__([val for val in self if val not in other])
|
| 369 |
+
|
| 370 |
+
def update(self, iterable):
|
| 371 |
+
for val in iterable:
|
| 372 |
+
self.add(val)
|
| 373 |
+
|
| 374 |
+
class TupleKind(Kind):
|
| 375 |
+
"""
|
| 376 |
+
TupleKind is a subclass of Kind, which is used to define Kind of ``Tuple``.
|
| 377 |
+
|
| 378 |
+
Parameters of TupleKind will be kinds of all the arguments in Tuples, for
|
| 379 |
+
example
|
| 380 |
+
|
| 381 |
+
Parameters
|
| 382 |
+
==========
|
| 383 |
+
|
| 384 |
+
args : tuple(element_kind)
|
| 385 |
+
element_kind is kind of element.
|
| 386 |
+
args is tuple of kinds of element
|
| 387 |
+
|
| 388 |
+
Examples
|
| 389 |
+
========
|
| 390 |
+
|
| 391 |
+
>>> from sympy import Tuple
|
| 392 |
+
>>> Tuple(1, 2).kind
|
| 393 |
+
TupleKind(NumberKind, NumberKind)
|
| 394 |
+
>>> Tuple(1, 2).kind.element_kind
|
| 395 |
+
(NumberKind, NumberKind)
|
| 396 |
+
|
| 397 |
+
See Also
|
| 398 |
+
========
|
| 399 |
+
|
| 400 |
+
sympy.core.kind.NumberKind
|
| 401 |
+
MatrixKind
|
| 402 |
+
sympy.sets.sets.SetKind
|
| 403 |
+
"""
|
| 404 |
+
def __new__(cls, *args):
|
| 405 |
+
obj = super().__new__(cls, *args)
|
| 406 |
+
obj.element_kind = args
|
| 407 |
+
return obj
|
| 408 |
+
|
| 409 |
+
def __repr__(self):
|
| 410 |
+
return "TupleKind{}".format(self.element_kind)
|
lib/python3.12/site-packages/sympy/core/core.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
""" The core's core. """
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class Registry:
|
| 6 |
+
"""
|
| 7 |
+
Base class for registry objects.
|
| 8 |
+
|
| 9 |
+
Registries map a name to an object using attribute notation. Registry
|
| 10 |
+
classes behave singletonically: all their instances share the same state,
|
| 11 |
+
which is stored in the class object.
|
| 12 |
+
|
| 13 |
+
All subclasses should set `__slots__ = ()`.
|
| 14 |
+
"""
|
| 15 |
+
__slots__ = ()
|
| 16 |
+
|
| 17 |
+
def __setattr__(self, name, obj):
|
| 18 |
+
setattr(self.__class__, name, obj)
|
| 19 |
+
|
| 20 |
+
def __delattr__(self, name):
|
| 21 |
+
delattr(self.__class__, name)
|
lib/python3.12/site-packages/sympy/core/coreerrors.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Definitions of common exceptions for :mod:`sympy.core` module. """
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class BaseCoreError(Exception):
|
| 5 |
+
"""Base class for core related exceptions. """
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class NonCommutativeExpression(BaseCoreError):
|
| 9 |
+
"""Raised when expression didn't have commutative property. """
|
lib/python3.12/site-packages/sympy/core/decorators.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SymPy core decorators.
|
| 3 |
+
|
| 4 |
+
The purpose of this module is to expose decorators without any other
|
| 5 |
+
dependencies, so that they can be easily imported anywhere in sympy/core.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from functools import wraps
|
| 9 |
+
from .sympify import SympifyError, sympify
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def _sympifyit(arg, retval=None):
|
| 13 |
+
"""
|
| 14 |
+
decorator to smartly _sympify function arguments
|
| 15 |
+
|
| 16 |
+
Explanation
|
| 17 |
+
===========
|
| 18 |
+
|
| 19 |
+
@_sympifyit('other', NotImplemented)
|
| 20 |
+
def add(self, other):
|
| 21 |
+
...
|
| 22 |
+
|
| 23 |
+
In add, other can be thought of as already being a SymPy object.
|
| 24 |
+
|
| 25 |
+
If it is not, the code is likely to catch an exception, then other will
|
| 26 |
+
be explicitly _sympified, and the whole code restarted.
|
| 27 |
+
|
| 28 |
+
if _sympify(arg) fails, NotImplemented will be returned
|
| 29 |
+
|
| 30 |
+
See also
|
| 31 |
+
========
|
| 32 |
+
|
| 33 |
+
__sympifyit
|
| 34 |
+
"""
|
| 35 |
+
def deco(func):
|
| 36 |
+
return __sympifyit(func, arg, retval)
|
| 37 |
+
|
| 38 |
+
return deco
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def __sympifyit(func, arg, retval=None):
|
| 42 |
+
"""Decorator to _sympify `arg` argument for function `func`.
|
| 43 |
+
|
| 44 |
+
Do not use directly -- use _sympifyit instead.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
# we support f(a,b) only
|
| 48 |
+
if not func.__code__.co_argcount:
|
| 49 |
+
raise LookupError("func not found")
|
| 50 |
+
# only b is _sympified
|
| 51 |
+
assert func.__code__.co_varnames[1] == arg
|
| 52 |
+
if retval is None:
|
| 53 |
+
@wraps(func)
|
| 54 |
+
def __sympifyit_wrapper(a, b):
|
| 55 |
+
return func(a, sympify(b, strict=True))
|
| 56 |
+
|
| 57 |
+
else:
|
| 58 |
+
@wraps(func)
|
| 59 |
+
def __sympifyit_wrapper(a, b):
|
| 60 |
+
try:
|
| 61 |
+
# If an external class has _op_priority, it knows how to deal
|
| 62 |
+
# with SymPy objects. Otherwise, it must be converted.
|
| 63 |
+
if not hasattr(b, '_op_priority'):
|
| 64 |
+
b = sympify(b, strict=True)
|
| 65 |
+
return func(a, b)
|
| 66 |
+
except SympifyError:
|
| 67 |
+
return retval
|
| 68 |
+
|
| 69 |
+
return __sympifyit_wrapper
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def call_highest_priority(method_name):
|
| 73 |
+
"""A decorator for binary special methods to handle _op_priority.
|
| 74 |
+
|
| 75 |
+
Explanation
|
| 76 |
+
===========
|
| 77 |
+
|
| 78 |
+
Binary special methods in Expr and its subclasses use a special attribute
|
| 79 |
+
'_op_priority' to determine whose special method will be called to
|
| 80 |
+
handle the operation. In general, the object having the highest value of
|
| 81 |
+
'_op_priority' will handle the operation. Expr and subclasses that define
|
| 82 |
+
custom binary special methods (__mul__, etc.) should decorate those
|
| 83 |
+
methods with this decorator to add the priority logic.
|
| 84 |
+
|
| 85 |
+
The ``method_name`` argument is the name of the method of the other class
|
| 86 |
+
that will be called. Use this decorator in the following manner::
|
| 87 |
+
|
| 88 |
+
# Call other.__rmul__ if other._op_priority > self._op_priority
|
| 89 |
+
@call_highest_priority('__rmul__')
|
| 90 |
+
def __mul__(self, other):
|
| 91 |
+
...
|
| 92 |
+
|
| 93 |
+
# Call other.__mul__ if other._op_priority > self._op_priority
|
| 94 |
+
@call_highest_priority('__mul__')
|
| 95 |
+
def __rmul__(self, other):
|
| 96 |
+
...
|
| 97 |
+
"""
|
| 98 |
+
def priority_decorator(func):
|
| 99 |
+
@wraps(func)
|
| 100 |
+
def binary_op_wrapper(self, other):
|
| 101 |
+
if hasattr(other, '_op_priority'):
|
| 102 |
+
if other._op_priority > self._op_priority:
|
| 103 |
+
f = getattr(other, method_name, None)
|
| 104 |
+
if f is not None:
|
| 105 |
+
return f(self)
|
| 106 |
+
return func(self, other)
|
| 107 |
+
return binary_op_wrapper
|
| 108 |
+
return priority_decorator
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def sympify_method_args(cls):
|
| 112 |
+
'''Decorator for a class with methods that sympify arguments.
|
| 113 |
+
|
| 114 |
+
Explanation
|
| 115 |
+
===========
|
| 116 |
+
|
| 117 |
+
The sympify_method_args decorator is to be used with the sympify_return
|
| 118 |
+
decorator for automatic sympification of method arguments. This is
|
| 119 |
+
intended for the common idiom of writing a class like :
|
| 120 |
+
|
| 121 |
+
Examples
|
| 122 |
+
========
|
| 123 |
+
|
| 124 |
+
>>> from sympy import Basic, SympifyError, S
|
| 125 |
+
>>> from sympy.core.sympify import _sympify
|
| 126 |
+
|
| 127 |
+
>>> class MyTuple(Basic):
|
| 128 |
+
... def __add__(self, other):
|
| 129 |
+
... try:
|
| 130 |
+
... other = _sympify(other)
|
| 131 |
+
... except SympifyError:
|
| 132 |
+
... return NotImplemented
|
| 133 |
+
... if not isinstance(other, MyTuple):
|
| 134 |
+
... return NotImplemented
|
| 135 |
+
... return MyTuple(*(self.args + other.args))
|
| 136 |
+
|
| 137 |
+
>>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4))
|
| 138 |
+
MyTuple(1, 2, 3, 4)
|
| 139 |
+
|
| 140 |
+
In the above it is important that we return NotImplemented when other is
|
| 141 |
+
not sympifiable and also when the sympified result is not of the expected
|
| 142 |
+
type. This allows the MyTuple class to be used cooperatively with other
|
| 143 |
+
classes that overload __add__ and want to do something else in combination
|
| 144 |
+
with instance of Tuple.
|
| 145 |
+
|
| 146 |
+
Using this decorator the above can be written as
|
| 147 |
+
|
| 148 |
+
>>> from sympy.core.decorators import sympify_method_args, sympify_return
|
| 149 |
+
|
| 150 |
+
>>> @sympify_method_args
|
| 151 |
+
... class MyTuple(Basic):
|
| 152 |
+
... @sympify_return([('other', 'MyTuple')], NotImplemented)
|
| 153 |
+
... def __add__(self, other):
|
| 154 |
+
... return MyTuple(*(self.args + other.args))
|
| 155 |
+
|
| 156 |
+
>>> MyTuple(S(1), S(2)) + MyTuple(S(3), S(4))
|
| 157 |
+
MyTuple(1, 2, 3, 4)
|
| 158 |
+
|
| 159 |
+
The idea here is that the decorators take care of the boiler-plate code
|
| 160 |
+
for making this happen in each method that potentially needs to accept
|
| 161 |
+
unsympified arguments. Then the body of e.g. the __add__ method can be
|
| 162 |
+
written without needing to worry about calling _sympify or checking the
|
| 163 |
+
type of the resulting object.
|
| 164 |
+
|
| 165 |
+
The parameters for sympify_return are a list of tuples of the form
|
| 166 |
+
(parameter_name, expected_type) and the value to return (e.g.
|
| 167 |
+
NotImplemented). The expected_type parameter can be a type e.g. Tuple or a
|
| 168 |
+
string 'Tuple'. Using a string is useful for specifying a Type within its
|
| 169 |
+
class body (as in the above example).
|
| 170 |
+
|
| 171 |
+
Notes: Currently sympify_return only works for methods that take a single
|
| 172 |
+
argument (not including self). Specifying an expected_type as a string
|
| 173 |
+
only works for the class in which the method is defined.
|
| 174 |
+
'''
|
| 175 |
+
# Extract the wrapped methods from each of the wrapper objects created by
|
| 176 |
+
# the sympify_return decorator. Doing this here allows us to provide the
|
| 177 |
+
# cls argument which is used for forward string referencing.
|
| 178 |
+
for attrname, obj in cls.__dict__.items():
|
| 179 |
+
if isinstance(obj, _SympifyWrapper):
|
| 180 |
+
setattr(cls, attrname, obj.make_wrapped(cls))
|
| 181 |
+
return cls
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def sympify_return(*args):
|
| 185 |
+
'''Function/method decorator to sympify arguments automatically
|
| 186 |
+
|
| 187 |
+
See the docstring of sympify_method_args for explanation.
|
| 188 |
+
'''
|
| 189 |
+
# Store a wrapper object for the decorated method
|
| 190 |
+
def wrapper(func):
|
| 191 |
+
return _SympifyWrapper(func, args)
|
| 192 |
+
return wrapper
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
class _SympifyWrapper:
|
| 196 |
+
'''Internal class used by sympify_return and sympify_method_args'''
|
| 197 |
+
|
| 198 |
+
def __init__(self, func, args):
|
| 199 |
+
self.func = func
|
| 200 |
+
self.args = args
|
| 201 |
+
|
| 202 |
+
def make_wrapped(self, cls):
|
| 203 |
+
func = self.func
|
| 204 |
+
parameters, retval = self.args
|
| 205 |
+
|
| 206 |
+
# XXX: Handle more than one parameter?
|
| 207 |
+
[(parameter, expectedcls)] = parameters
|
| 208 |
+
|
| 209 |
+
# Handle forward references to the current class using strings
|
| 210 |
+
if expectedcls == cls.__name__:
|
| 211 |
+
expectedcls = cls
|
| 212 |
+
|
| 213 |
+
# Raise RuntimeError since this is a failure at import time and should
|
| 214 |
+
# not be recoverable.
|
| 215 |
+
nargs = func.__code__.co_argcount
|
| 216 |
+
# we support f(a, b) only
|
| 217 |
+
if nargs != 2:
|
| 218 |
+
raise RuntimeError('sympify_return can only be used with 2 argument functions')
|
| 219 |
+
# only b is _sympified
|
| 220 |
+
if func.__code__.co_varnames[1] != parameter:
|
| 221 |
+
raise RuntimeError('parameter name mismatch "%s" in %s' %
|
| 222 |
+
(parameter, func.__name__))
|
| 223 |
+
|
| 224 |
+
@wraps(func)
|
| 225 |
+
def _func(self, other):
|
| 226 |
+
# XXX: The check for _op_priority here should be removed. It is
|
| 227 |
+
# needed to stop mutable matrices from being sympified to
|
| 228 |
+
# immutable matrices which breaks things in quantum...
|
| 229 |
+
if not hasattr(other, '_op_priority'):
|
| 230 |
+
try:
|
| 231 |
+
other = sympify(other, strict=True)
|
| 232 |
+
except SympifyError:
|
| 233 |
+
return retval
|
| 234 |
+
if not isinstance(other, expectedcls):
|
| 235 |
+
return retval
|
| 236 |
+
return func(self, other)
|
| 237 |
+
|
| 238 |
+
return _func
|
lib/python3.12/site-packages/sympy/core/evalf.py
ADDED
|
@@ -0,0 +1,1802 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Adaptive numerical evaluation of SymPy expressions, using mpmath
|
| 3 |
+
for mathematical functions.
|
| 4 |
+
"""
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
from typing import Tuple as tTuple, Optional, Union as tUnion, Callable, List, Dict as tDict, Type, TYPE_CHECKING, \
|
| 7 |
+
Any, overload
|
| 8 |
+
|
| 9 |
+
import math
|
| 10 |
+
|
| 11 |
+
import mpmath.libmp as libmp
|
| 12 |
+
from mpmath import (
|
| 13 |
+
make_mpc, make_mpf, mp, mpc, mpf, nsum, quadts, quadosc, workprec)
|
| 14 |
+
from mpmath import inf as mpmath_inf
|
| 15 |
+
from mpmath.libmp import (from_int, from_man_exp, from_rational, fhalf,
|
| 16 |
+
fnan, finf, fninf, fnone, fone, fzero, mpf_abs, mpf_add,
|
| 17 |
+
mpf_atan, mpf_atan2, mpf_cmp, mpf_cos, mpf_e, mpf_exp, mpf_log, mpf_lt,
|
| 18 |
+
mpf_mul, mpf_neg, mpf_pi, mpf_pow, mpf_pow_int, mpf_shift, mpf_sin,
|
| 19 |
+
mpf_sqrt, normalize, round_nearest, to_int, to_str)
|
| 20 |
+
from mpmath.libmp import bitcount as mpmath_bitcount
|
| 21 |
+
from mpmath.libmp.backend import MPZ
|
| 22 |
+
from mpmath.libmp.libmpc import _infs_nan
|
| 23 |
+
from mpmath.libmp.libmpf import dps_to_prec, prec_to_dps
|
| 24 |
+
|
| 25 |
+
from .sympify import sympify
|
| 26 |
+
from .singleton import S
|
| 27 |
+
from sympy.external.gmpy import SYMPY_INTS
|
| 28 |
+
from sympy.utilities.iterables import is_sequence
|
| 29 |
+
from sympy.utilities.lambdify import lambdify
|
| 30 |
+
from sympy.utilities.misc import as_int
|
| 31 |
+
|
| 32 |
+
if TYPE_CHECKING:
|
| 33 |
+
from sympy.core.expr import Expr
|
| 34 |
+
from sympy.core.add import Add
|
| 35 |
+
from sympy.core.mul import Mul
|
| 36 |
+
from sympy.core.power import Pow
|
| 37 |
+
from sympy.core.symbol import Symbol
|
| 38 |
+
from sympy.integrals.integrals import Integral
|
| 39 |
+
from sympy.concrete.summations import Sum
|
| 40 |
+
from sympy.concrete.products import Product
|
| 41 |
+
from sympy.functions.elementary.exponential import exp, log
|
| 42 |
+
from sympy.functions.elementary.complexes import Abs, re, im
|
| 43 |
+
from sympy.functions.elementary.integers import ceiling, floor
|
| 44 |
+
from sympy.functions.elementary.trigonometric import atan
|
| 45 |
+
from .numbers import Float, Rational, Integer, AlgebraicNumber, Number
|
| 46 |
+
|
| 47 |
+
LG10 = math.log2(10)
|
| 48 |
+
rnd = round_nearest
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def bitcount(n):
|
| 52 |
+
"""Return smallest integer, b, such that |n|/2**b < 1.
|
| 53 |
+
"""
|
| 54 |
+
return mpmath_bitcount(abs(int(n)))
|
| 55 |
+
|
| 56 |
+
# Used in a few places as placeholder values to denote exponents and
|
| 57 |
+
# precision levels, e.g. of exact numbers. Must be careful to avoid
|
| 58 |
+
# passing these to mpmath functions or returning them in final results.
|
| 59 |
+
INF = float(mpmath_inf)
|
| 60 |
+
MINUS_INF = float(-mpmath_inf)
|
| 61 |
+
|
| 62 |
+
# ~= 100 digits. Real men set this to INF.
|
| 63 |
+
DEFAULT_MAXPREC = 333
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
class PrecisionExhausted(ArithmeticError):
|
| 67 |
+
pass
|
| 68 |
+
|
| 69 |
+
#----------------------------------------------------------------------------#
|
| 70 |
+
# #
|
| 71 |
+
# Helper functions for arithmetic and complex parts #
|
| 72 |
+
# #
|
| 73 |
+
#----------------------------------------------------------------------------#
|
| 74 |
+
|
| 75 |
+
"""
|
| 76 |
+
An mpf value tuple is a tuple of integers (sign, man, exp, bc)
|
| 77 |
+
representing a floating-point number: [1, -1][sign]*man*2**exp where
|
| 78 |
+
sign is 0 or 1 and bc should correspond to the number of bits used to
|
| 79 |
+
represent the mantissa (man) in binary notation, e.g.
|
| 80 |
+
"""
|
| 81 |
+
MPF_TUP = tTuple[int, int, int, int] # mpf value tuple
|
| 82 |
+
|
| 83 |
+
"""
|
| 84 |
+
Explanation
|
| 85 |
+
===========
|
| 86 |
+
|
| 87 |
+
>>> from sympy.core.evalf import bitcount
|
| 88 |
+
>>> sign, man, exp, bc = 0, 5, 1, 3
|
| 89 |
+
>>> n = [1, -1][sign]*man*2**exp
|
| 90 |
+
>>> n, bitcount(man)
|
| 91 |
+
(10, 3)
|
| 92 |
+
|
| 93 |
+
A temporary result is a tuple (re, im, re_acc, im_acc) where
|
| 94 |
+
re and im are nonzero mpf value tuples representing approximate
|
| 95 |
+
numbers, or None to denote exact zeros.
|
| 96 |
+
|
| 97 |
+
re_acc, im_acc are integers denoting log2(e) where e is the estimated
|
| 98 |
+
relative accuracy of the respective complex part, but may be anything
|
| 99 |
+
if the corresponding complex part is None.
|
| 100 |
+
|
| 101 |
+
"""
|
| 102 |
+
TMP_RES = Any # temporary result, should be some variant of
|
| 103 |
+
# tUnion[tTuple[Optional[MPF_TUP], Optional[MPF_TUP],
|
| 104 |
+
# Optional[int], Optional[int]],
|
| 105 |
+
# 'ComplexInfinity']
|
| 106 |
+
# but mypy reports error because it doesn't know as we know
|
| 107 |
+
# 1. re and re_acc are either both None or both MPF_TUP
|
| 108 |
+
# 2. sometimes the result can't be zoo
|
| 109 |
+
|
| 110 |
+
# type of the "options" parameter in internal evalf functions
|
| 111 |
+
OPT_DICT = tDict[str, Any]
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def fastlog(x: Optional[MPF_TUP]) -> tUnion[int, Any]:
|
| 115 |
+
"""Fast approximation of log2(x) for an mpf value tuple x.
|
| 116 |
+
|
| 117 |
+
Explanation
|
| 118 |
+
===========
|
| 119 |
+
|
| 120 |
+
Calculated as exponent + width of mantissa. This is an
|
| 121 |
+
approximation for two reasons: 1) it gives the ceil(log2(abs(x)))
|
| 122 |
+
value and 2) it is too high by 1 in the case that x is an exact
|
| 123 |
+
power of 2. Although this is easy to remedy by testing to see if
|
| 124 |
+
the odd mpf mantissa is 1 (indicating that one was dealing with
|
| 125 |
+
an exact power of 2) that would decrease the speed and is not
|
| 126 |
+
necessary as this is only being used as an approximation for the
|
| 127 |
+
number of bits in x. The correct return value could be written as
|
| 128 |
+
"x[2] + (x[3] if x[1] != 1 else 0)".
|
| 129 |
+
Since mpf tuples always have an odd mantissa, no check is done
|
| 130 |
+
to see if the mantissa is a multiple of 2 (in which case the
|
| 131 |
+
result would be too large by 1).
|
| 132 |
+
|
| 133 |
+
Examples
|
| 134 |
+
========
|
| 135 |
+
|
| 136 |
+
>>> from sympy import log
|
| 137 |
+
>>> from sympy.core.evalf import fastlog, bitcount
|
| 138 |
+
>>> s, m, e = 0, 5, 1
|
| 139 |
+
>>> bc = bitcount(m)
|
| 140 |
+
>>> n = [1, -1][s]*m*2**e
|
| 141 |
+
>>> n, (log(n)/log(2)).evalf(2), fastlog((s, m, e, bc))
|
| 142 |
+
(10, 3.3, 4)
|
| 143 |
+
"""
|
| 144 |
+
|
| 145 |
+
if not x or x == fzero:
|
| 146 |
+
return MINUS_INF
|
| 147 |
+
return x[2] + x[3]
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def pure_complex(v: 'Expr', or_real=False) -> tuple['Number', 'Number'] | None:
|
| 151 |
+
"""Return a and b if v matches a + I*b where b is not zero and
|
| 152 |
+
a and b are Numbers, else None. If `or_real` is True then 0 will
|
| 153 |
+
be returned for `b` if `v` is a real number.
|
| 154 |
+
|
| 155 |
+
Examples
|
| 156 |
+
========
|
| 157 |
+
|
| 158 |
+
>>> from sympy.core.evalf import pure_complex
|
| 159 |
+
>>> from sympy import sqrt, I, S
|
| 160 |
+
>>> a, b, surd = S(2), S(3), sqrt(2)
|
| 161 |
+
>>> pure_complex(a)
|
| 162 |
+
>>> pure_complex(a, or_real=True)
|
| 163 |
+
(2, 0)
|
| 164 |
+
>>> pure_complex(surd)
|
| 165 |
+
>>> pure_complex(a + b*I)
|
| 166 |
+
(2, 3)
|
| 167 |
+
>>> pure_complex(I)
|
| 168 |
+
(0, 1)
|
| 169 |
+
"""
|
| 170 |
+
h, t = v.as_coeff_Add()
|
| 171 |
+
if t:
|
| 172 |
+
c, i = t.as_coeff_Mul()
|
| 173 |
+
if i is S.ImaginaryUnit:
|
| 174 |
+
return h, c
|
| 175 |
+
elif or_real:
|
| 176 |
+
return h, S.Zero
|
| 177 |
+
return None
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
# I don't know what this is, see function scaled_zero below
|
| 181 |
+
SCALED_ZERO_TUP = tTuple[List[int], int, int, int]
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
@overload
|
| 185 |
+
def scaled_zero(mag: SCALED_ZERO_TUP, sign=1) -> MPF_TUP:
|
| 186 |
+
...
|
| 187 |
+
@overload
|
| 188 |
+
def scaled_zero(mag: int, sign=1) -> tTuple[SCALED_ZERO_TUP, int]:
|
| 189 |
+
...
|
| 190 |
+
def scaled_zero(mag: tUnion[SCALED_ZERO_TUP, int], sign=1) -> \
|
| 191 |
+
tUnion[MPF_TUP, tTuple[SCALED_ZERO_TUP, int]]:
|
| 192 |
+
"""Return an mpf representing a power of two with magnitude ``mag``
|
| 193 |
+
and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just
|
| 194 |
+
remove the sign from within the list that it was initially wrapped
|
| 195 |
+
in.
|
| 196 |
+
|
| 197 |
+
Examples
|
| 198 |
+
========
|
| 199 |
+
|
| 200 |
+
>>> from sympy.core.evalf import scaled_zero
|
| 201 |
+
>>> from sympy import Float
|
| 202 |
+
>>> z, p = scaled_zero(100)
|
| 203 |
+
>>> z, p
|
| 204 |
+
(([0], 1, 100, 1), -1)
|
| 205 |
+
>>> ok = scaled_zero(z)
|
| 206 |
+
>>> ok
|
| 207 |
+
(0, 1, 100, 1)
|
| 208 |
+
>>> Float(ok)
|
| 209 |
+
1.26765060022823e+30
|
| 210 |
+
>>> Float(ok, p)
|
| 211 |
+
0.e+30
|
| 212 |
+
>>> ok, p = scaled_zero(100, -1)
|
| 213 |
+
>>> Float(scaled_zero(ok), p)
|
| 214 |
+
-0.e+30
|
| 215 |
+
"""
|
| 216 |
+
if isinstance(mag, tuple) and len(mag) == 4 and iszero(mag, scaled=True):
|
| 217 |
+
return (mag[0][0],) + mag[1:]
|
| 218 |
+
elif isinstance(mag, SYMPY_INTS):
|
| 219 |
+
if sign not in [-1, 1]:
|
| 220 |
+
raise ValueError('sign must be +/-1')
|
| 221 |
+
rv, p = mpf_shift(fone, mag), -1
|
| 222 |
+
s = 0 if sign == 1 else 1
|
| 223 |
+
rv = ([s],) + rv[1:]
|
| 224 |
+
return rv, p
|
| 225 |
+
else:
|
| 226 |
+
raise ValueError('scaled zero expects int or scaled_zero tuple.')
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
def iszero(mpf: tUnion[MPF_TUP, SCALED_ZERO_TUP, None], scaled=False) -> Optional[bool]:
|
| 230 |
+
if not scaled:
|
| 231 |
+
return not mpf or not mpf[1] and not mpf[-1]
|
| 232 |
+
return mpf and isinstance(mpf[0], list) and mpf[1] == mpf[-1] == 1
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
def complex_accuracy(result: TMP_RES) -> tUnion[int, Any]:
|
| 236 |
+
"""
|
| 237 |
+
Returns relative accuracy of a complex number with given accuracies
|
| 238 |
+
for the real and imaginary parts. The relative accuracy is defined
|
| 239 |
+
in the complex norm sense as ||z|+|error|| / |z| where error
|
| 240 |
+
is equal to (real absolute error) + (imag absolute error)*i.
|
| 241 |
+
|
| 242 |
+
The full expression for the (logarithmic) error can be approximated
|
| 243 |
+
easily by using the max norm to approximate the complex norm.
|
| 244 |
+
|
| 245 |
+
In the worst case (re and im equal), this is wrong by a factor
|
| 246 |
+
sqrt(2), or by log2(sqrt(2)) = 0.5 bit.
|
| 247 |
+
"""
|
| 248 |
+
if result is S.ComplexInfinity:
|
| 249 |
+
return INF
|
| 250 |
+
re, im, re_acc, im_acc = result
|
| 251 |
+
if not im:
|
| 252 |
+
if not re:
|
| 253 |
+
return INF
|
| 254 |
+
return re_acc
|
| 255 |
+
if not re:
|
| 256 |
+
return im_acc
|
| 257 |
+
re_size = fastlog(re)
|
| 258 |
+
im_size = fastlog(im)
|
| 259 |
+
absolute_error = max(re_size - re_acc, im_size - im_acc)
|
| 260 |
+
relative_error = absolute_error - max(re_size, im_size)
|
| 261 |
+
return -relative_error
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def get_abs(expr: 'Expr', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 265 |
+
result = evalf(expr, prec + 2, options)
|
| 266 |
+
if result is S.ComplexInfinity:
|
| 267 |
+
return finf, None, prec, None
|
| 268 |
+
re, im, re_acc, im_acc = result
|
| 269 |
+
if not re:
|
| 270 |
+
re, re_acc, im, im_acc = im, im_acc, re, re_acc
|
| 271 |
+
if im:
|
| 272 |
+
if expr.is_number:
|
| 273 |
+
abs_expr, _, acc, _ = evalf(abs(N(expr, prec + 2)),
|
| 274 |
+
prec + 2, options)
|
| 275 |
+
return abs_expr, None, acc, None
|
| 276 |
+
else:
|
| 277 |
+
if 'subs' in options:
|
| 278 |
+
return libmp.mpc_abs((re, im), prec), None, re_acc, None
|
| 279 |
+
return abs(expr), None, prec, None
|
| 280 |
+
elif re:
|
| 281 |
+
return mpf_abs(re), None, re_acc, None
|
| 282 |
+
else:
|
| 283 |
+
return None, None, None, None
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def get_complex_part(expr: 'Expr', no: int, prec: int, options: OPT_DICT) -> TMP_RES:
|
| 287 |
+
"""no = 0 for real part, no = 1 for imaginary part"""
|
| 288 |
+
workprec = prec
|
| 289 |
+
i = 0
|
| 290 |
+
while 1:
|
| 291 |
+
res = evalf(expr, workprec, options)
|
| 292 |
+
if res is S.ComplexInfinity:
|
| 293 |
+
return fnan, None, prec, None
|
| 294 |
+
value, accuracy = res[no::2]
|
| 295 |
+
# XXX is the last one correct? Consider re((1+I)**2).n()
|
| 296 |
+
if (not value) or accuracy >= prec or -value[2] > prec:
|
| 297 |
+
return value, None, accuracy, None
|
| 298 |
+
workprec += max(30, 2**i)
|
| 299 |
+
i += 1
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
def evalf_abs(expr: 'Abs', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 303 |
+
return get_abs(expr.args[0], prec, options)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
def evalf_re(expr: 're', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 307 |
+
return get_complex_part(expr.args[0], 0, prec, options)
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
def evalf_im(expr: 'im', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 311 |
+
return get_complex_part(expr.args[0], 1, prec, options)
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
def finalize_complex(re: MPF_TUP, im: MPF_TUP, prec: int) -> TMP_RES:
|
| 315 |
+
if re == fzero and im == fzero:
|
| 316 |
+
raise ValueError("got complex zero with unknown accuracy")
|
| 317 |
+
elif re == fzero:
|
| 318 |
+
return None, im, None, prec
|
| 319 |
+
elif im == fzero:
|
| 320 |
+
return re, None, prec, None
|
| 321 |
+
|
| 322 |
+
size_re = fastlog(re)
|
| 323 |
+
size_im = fastlog(im)
|
| 324 |
+
if size_re > size_im:
|
| 325 |
+
re_acc = prec
|
| 326 |
+
im_acc = prec + min(-(size_re - size_im), 0)
|
| 327 |
+
else:
|
| 328 |
+
im_acc = prec
|
| 329 |
+
re_acc = prec + min(-(size_im - size_re), 0)
|
| 330 |
+
return re, im, re_acc, im_acc
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
def chop_parts(value: TMP_RES, prec: int) -> TMP_RES:
|
| 334 |
+
"""
|
| 335 |
+
Chop off tiny real or complex parts.
|
| 336 |
+
"""
|
| 337 |
+
if value is S.ComplexInfinity:
|
| 338 |
+
return value
|
| 339 |
+
re, im, re_acc, im_acc = value
|
| 340 |
+
# Method 1: chop based on absolute value
|
| 341 |
+
if re and re not in _infs_nan and (fastlog(re) < -prec + 4):
|
| 342 |
+
re, re_acc = None, None
|
| 343 |
+
if im and im not in _infs_nan and (fastlog(im) < -prec + 4):
|
| 344 |
+
im, im_acc = None, None
|
| 345 |
+
# Method 2: chop if inaccurate and relatively small
|
| 346 |
+
if re and im:
|
| 347 |
+
delta = fastlog(re) - fastlog(im)
|
| 348 |
+
if re_acc < 2 and (delta - re_acc <= -prec + 4):
|
| 349 |
+
re, re_acc = None, None
|
| 350 |
+
if im_acc < 2 and (delta - im_acc >= prec - 4):
|
| 351 |
+
im, im_acc = None, None
|
| 352 |
+
return re, im, re_acc, im_acc
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def check_target(expr: 'Expr', result: TMP_RES, prec: int):
|
| 356 |
+
a = complex_accuracy(result)
|
| 357 |
+
if a < prec:
|
| 358 |
+
raise PrecisionExhausted("Failed to distinguish the expression: \n\n%s\n\n"
|
| 359 |
+
"from zero. Try simplifying the input, using chop=True, or providing "
|
| 360 |
+
"a higher maxn for evalf" % (expr))
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
def get_integer_part(expr: 'Expr', no: int, options: OPT_DICT, return_ints=False) -> \
|
| 364 |
+
tUnion[TMP_RES, tTuple[int, int]]:
|
| 365 |
+
"""
|
| 366 |
+
With no = 1, computes ceiling(expr)
|
| 367 |
+
With no = -1, computes floor(expr)
|
| 368 |
+
|
| 369 |
+
Note: this function either gives the exact result or signals failure.
|
| 370 |
+
"""
|
| 371 |
+
from sympy.functions.elementary.complexes import re, im
|
| 372 |
+
# The expression is likely less than 2^30 or so
|
| 373 |
+
assumed_size = 30
|
| 374 |
+
result = evalf(expr, assumed_size, options)
|
| 375 |
+
if result is S.ComplexInfinity:
|
| 376 |
+
raise ValueError("Cannot get integer part of Complex Infinity")
|
| 377 |
+
ire, iim, ire_acc, iim_acc = result
|
| 378 |
+
|
| 379 |
+
# We now know the size, so we can calculate how much extra precision
|
| 380 |
+
# (if any) is needed to get within the nearest integer
|
| 381 |
+
if ire and iim:
|
| 382 |
+
gap = max(fastlog(ire) - ire_acc, fastlog(iim) - iim_acc)
|
| 383 |
+
elif ire:
|
| 384 |
+
gap = fastlog(ire) - ire_acc
|
| 385 |
+
elif iim:
|
| 386 |
+
gap = fastlog(iim) - iim_acc
|
| 387 |
+
else:
|
| 388 |
+
# ... or maybe the expression was exactly zero
|
| 389 |
+
if return_ints:
|
| 390 |
+
return 0, 0
|
| 391 |
+
else:
|
| 392 |
+
return None, None, None, None
|
| 393 |
+
|
| 394 |
+
margin = 10
|
| 395 |
+
|
| 396 |
+
if gap >= -margin:
|
| 397 |
+
prec = margin + assumed_size + gap
|
| 398 |
+
ire, iim, ire_acc, iim_acc = evalf(
|
| 399 |
+
expr, prec, options)
|
| 400 |
+
else:
|
| 401 |
+
prec = assumed_size
|
| 402 |
+
|
| 403 |
+
# We can now easily find the nearest integer, but to find floor/ceil, we
|
| 404 |
+
# must also calculate whether the difference to the nearest integer is
|
| 405 |
+
# positive or negative (which may fail if very close).
|
| 406 |
+
def calc_part(re_im: 'Expr', nexpr: MPF_TUP):
|
| 407 |
+
from .add import Add
|
| 408 |
+
_, _, exponent, _ = nexpr
|
| 409 |
+
is_int = exponent == 0
|
| 410 |
+
nint = int(to_int(nexpr, rnd))
|
| 411 |
+
if is_int:
|
| 412 |
+
# make sure that we had enough precision to distinguish
|
| 413 |
+
# between nint and the re or im part (re_im) of expr that
|
| 414 |
+
# was passed to calc_part
|
| 415 |
+
ire, iim, ire_acc, iim_acc = evalf(
|
| 416 |
+
re_im - nint, 10, options) # don't need much precision
|
| 417 |
+
assert not iim
|
| 418 |
+
size = -fastlog(ire) + 2 # -ve b/c ire is less than 1
|
| 419 |
+
if size > prec:
|
| 420 |
+
ire, iim, ire_acc, iim_acc = evalf(
|
| 421 |
+
re_im, size, options)
|
| 422 |
+
assert not iim
|
| 423 |
+
nexpr = ire
|
| 424 |
+
nint = int(to_int(nexpr, rnd))
|
| 425 |
+
_, _, new_exp, _ = ire
|
| 426 |
+
is_int = new_exp == 0
|
| 427 |
+
if not is_int:
|
| 428 |
+
# if there are subs and they all contain integer re/im parts
|
| 429 |
+
# then we can (hopefully) safely substitute them into the
|
| 430 |
+
# expression
|
| 431 |
+
s = options.get('subs', False)
|
| 432 |
+
if s:
|
| 433 |
+
# use strict=False with as_int because we take
|
| 434 |
+
# 2.0 == 2
|
| 435 |
+
def is_int_reim(x):
|
| 436 |
+
"""Check for integer or integer + I*integer."""
|
| 437 |
+
try:
|
| 438 |
+
as_int(x, strict=False)
|
| 439 |
+
return True
|
| 440 |
+
except ValueError:
|
| 441 |
+
try:
|
| 442 |
+
[as_int(i, strict=False) for i in x.as_real_imag()]
|
| 443 |
+
return True
|
| 444 |
+
except ValueError:
|
| 445 |
+
return False
|
| 446 |
+
|
| 447 |
+
if all(is_int_reim(v) for v in s.values()):
|
| 448 |
+
re_im = re_im.subs(s)
|
| 449 |
+
|
| 450 |
+
re_im = Add(re_im, -nint, evaluate=False)
|
| 451 |
+
x, _, x_acc, _ = evalf(re_im, 10, options)
|
| 452 |
+
try:
|
| 453 |
+
check_target(re_im, (x, None, x_acc, None), 3)
|
| 454 |
+
except PrecisionExhausted:
|
| 455 |
+
if not re_im.equals(0):
|
| 456 |
+
raise PrecisionExhausted
|
| 457 |
+
x = fzero
|
| 458 |
+
nint += int(no*(mpf_cmp(x or fzero, fzero) == no))
|
| 459 |
+
nint = from_int(nint)
|
| 460 |
+
return nint, INF
|
| 461 |
+
|
| 462 |
+
re_, im_, re_acc, im_acc = None, None, None, None
|
| 463 |
+
|
| 464 |
+
if ire:
|
| 465 |
+
re_, re_acc = calc_part(re(expr, evaluate=False), ire)
|
| 466 |
+
if iim:
|
| 467 |
+
im_, im_acc = calc_part(im(expr, evaluate=False), iim)
|
| 468 |
+
|
| 469 |
+
if return_ints:
|
| 470 |
+
return int(to_int(re_ or fzero)), int(to_int(im_ or fzero))
|
| 471 |
+
return re_, im_, re_acc, im_acc
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def evalf_ceiling(expr: 'ceiling', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 475 |
+
return get_integer_part(expr.args[0], 1, options)
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
def evalf_floor(expr: 'floor', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 479 |
+
return get_integer_part(expr.args[0], -1, options)
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
def evalf_float(expr: 'Float', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 483 |
+
return expr._mpf_, None, prec, None
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
def evalf_rational(expr: 'Rational', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 487 |
+
return from_rational(expr.p, expr.q, prec), None, prec, None
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
def evalf_integer(expr: 'Integer', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 491 |
+
return from_int(expr.p, prec), None, prec, None
|
| 492 |
+
|
| 493 |
+
#----------------------------------------------------------------------------#
|
| 494 |
+
# #
|
| 495 |
+
# Arithmetic operations #
|
| 496 |
+
# #
|
| 497 |
+
#----------------------------------------------------------------------------#
|
| 498 |
+
|
| 499 |
+
|
| 500 |
+
def add_terms(terms: list, prec: int, target_prec: int) -> \
|
| 501 |
+
tTuple[tUnion[MPF_TUP, SCALED_ZERO_TUP, None], Optional[int]]:
|
| 502 |
+
"""
|
| 503 |
+
Helper for evalf_add. Adds a list of (mpfval, accuracy) terms.
|
| 504 |
+
|
| 505 |
+
Returns
|
| 506 |
+
=======
|
| 507 |
+
|
| 508 |
+
- None, None if there are no non-zero terms;
|
| 509 |
+
- terms[0] if there is only 1 term;
|
| 510 |
+
- scaled_zero if the sum of the terms produces a zero by cancellation
|
| 511 |
+
e.g. mpfs representing 1 and -1 would produce a scaled zero which need
|
| 512 |
+
special handling since they are not actually zero and they are purposely
|
| 513 |
+
malformed to ensure that they cannot be used in anything but accuracy
|
| 514 |
+
calculations;
|
| 515 |
+
- a tuple that is scaled to target_prec that corresponds to the
|
| 516 |
+
sum of the terms.
|
| 517 |
+
|
| 518 |
+
The returned mpf tuple will be normalized to target_prec; the input
|
| 519 |
+
prec is used to define the working precision.
|
| 520 |
+
|
| 521 |
+
XXX explain why this is needed and why one cannot just loop using mpf_add
|
| 522 |
+
"""
|
| 523 |
+
|
| 524 |
+
terms = [t for t in terms if not iszero(t[0])]
|
| 525 |
+
if not terms:
|
| 526 |
+
return None, None
|
| 527 |
+
elif len(terms) == 1:
|
| 528 |
+
return terms[0]
|
| 529 |
+
|
| 530 |
+
# see if any argument is NaN or oo and thus warrants a special return
|
| 531 |
+
special = []
|
| 532 |
+
from .numbers import Float
|
| 533 |
+
for t in terms:
|
| 534 |
+
arg = Float._new(t[0], 1)
|
| 535 |
+
if arg is S.NaN or arg.is_infinite:
|
| 536 |
+
special.append(arg)
|
| 537 |
+
if special:
|
| 538 |
+
from .add import Add
|
| 539 |
+
rv = evalf(Add(*special), prec + 4, {})
|
| 540 |
+
return rv[0], rv[2]
|
| 541 |
+
|
| 542 |
+
working_prec = 2*prec
|
| 543 |
+
sum_man, sum_exp = 0, 0
|
| 544 |
+
absolute_err: List[int] = []
|
| 545 |
+
|
| 546 |
+
for x, accuracy in terms:
|
| 547 |
+
sign, man, exp, bc = x
|
| 548 |
+
if sign:
|
| 549 |
+
man = -man
|
| 550 |
+
absolute_err.append(bc + exp - accuracy)
|
| 551 |
+
delta = exp - sum_exp
|
| 552 |
+
if exp >= sum_exp:
|
| 553 |
+
# x much larger than existing sum?
|
| 554 |
+
# first: quick test
|
| 555 |
+
if ((delta > working_prec) and
|
| 556 |
+
((not sum_man) or
|
| 557 |
+
delta - bitcount(abs(sum_man)) > working_prec)):
|
| 558 |
+
sum_man = man
|
| 559 |
+
sum_exp = exp
|
| 560 |
+
else:
|
| 561 |
+
sum_man += (man << delta)
|
| 562 |
+
else:
|
| 563 |
+
delta = -delta
|
| 564 |
+
# x much smaller than existing sum?
|
| 565 |
+
if delta - bc > working_prec:
|
| 566 |
+
if not sum_man:
|
| 567 |
+
sum_man, sum_exp = man, exp
|
| 568 |
+
else:
|
| 569 |
+
sum_man = (sum_man << delta) + man
|
| 570 |
+
sum_exp = exp
|
| 571 |
+
absolute_error = max(absolute_err)
|
| 572 |
+
if not sum_man:
|
| 573 |
+
return scaled_zero(absolute_error)
|
| 574 |
+
if sum_man < 0:
|
| 575 |
+
sum_sign = 1
|
| 576 |
+
sum_man = -sum_man
|
| 577 |
+
else:
|
| 578 |
+
sum_sign = 0
|
| 579 |
+
sum_bc = bitcount(sum_man)
|
| 580 |
+
sum_accuracy = sum_exp + sum_bc - absolute_error
|
| 581 |
+
r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec,
|
| 582 |
+
rnd), sum_accuracy
|
| 583 |
+
return r
|
| 584 |
+
|
| 585 |
+
|
| 586 |
+
def evalf_add(v: 'Add', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 587 |
+
res = pure_complex(v)
|
| 588 |
+
if res:
|
| 589 |
+
h, c = res
|
| 590 |
+
re, _, re_acc, _ = evalf(h, prec, options)
|
| 591 |
+
im, _, im_acc, _ = evalf(c, prec, options)
|
| 592 |
+
return re, im, re_acc, im_acc
|
| 593 |
+
|
| 594 |
+
oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC)
|
| 595 |
+
|
| 596 |
+
i = 0
|
| 597 |
+
target_prec = prec
|
| 598 |
+
while 1:
|
| 599 |
+
options['maxprec'] = min(oldmaxprec, 2*prec)
|
| 600 |
+
|
| 601 |
+
terms = [evalf(arg, prec + 10, options) for arg in v.args]
|
| 602 |
+
n = terms.count(S.ComplexInfinity)
|
| 603 |
+
if n >= 2:
|
| 604 |
+
return fnan, None, prec, None
|
| 605 |
+
re, re_acc = add_terms(
|
| 606 |
+
[a[0::2] for a in terms if isinstance(a, tuple) and a[0]], prec, target_prec)
|
| 607 |
+
im, im_acc = add_terms(
|
| 608 |
+
[a[1::2] for a in terms if isinstance(a, tuple) and a[1]], prec, target_prec)
|
| 609 |
+
if n == 1:
|
| 610 |
+
if re in (finf, fninf, fnan) or im in (finf, fninf, fnan):
|
| 611 |
+
return fnan, None, prec, None
|
| 612 |
+
return S.ComplexInfinity
|
| 613 |
+
acc = complex_accuracy((re, im, re_acc, im_acc))
|
| 614 |
+
if acc >= target_prec:
|
| 615 |
+
if options.get('verbose'):
|
| 616 |
+
print("ADD: wanted", target_prec, "accurate bits, got", re_acc, im_acc)
|
| 617 |
+
break
|
| 618 |
+
else:
|
| 619 |
+
if (prec - target_prec) > options['maxprec']:
|
| 620 |
+
break
|
| 621 |
+
|
| 622 |
+
prec = prec + max(10 + 2**i, target_prec - acc)
|
| 623 |
+
i += 1
|
| 624 |
+
if options.get('verbose'):
|
| 625 |
+
print("ADD: restarting with prec", prec)
|
| 626 |
+
|
| 627 |
+
options['maxprec'] = oldmaxprec
|
| 628 |
+
if iszero(re, scaled=True):
|
| 629 |
+
re = scaled_zero(re)
|
| 630 |
+
if iszero(im, scaled=True):
|
| 631 |
+
im = scaled_zero(im)
|
| 632 |
+
return re, im, re_acc, im_acc
|
| 633 |
+
|
| 634 |
+
|
| 635 |
+
def evalf_mul(v: 'Mul', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 636 |
+
res = pure_complex(v)
|
| 637 |
+
if res:
|
| 638 |
+
# the only pure complex that is a mul is h*I
|
| 639 |
+
_, h = res
|
| 640 |
+
im, _, im_acc, _ = evalf(h, prec, options)
|
| 641 |
+
return None, im, None, im_acc
|
| 642 |
+
args = list(v.args)
|
| 643 |
+
|
| 644 |
+
# see if any argument is NaN or oo and thus warrants a special return
|
| 645 |
+
has_zero = False
|
| 646 |
+
special = []
|
| 647 |
+
from .numbers import Float
|
| 648 |
+
for arg in args:
|
| 649 |
+
result = evalf(arg, prec, options)
|
| 650 |
+
if result is S.ComplexInfinity:
|
| 651 |
+
special.append(result)
|
| 652 |
+
continue
|
| 653 |
+
if result[0] is None:
|
| 654 |
+
if result[1] is None:
|
| 655 |
+
has_zero = True
|
| 656 |
+
continue
|
| 657 |
+
num = Float._new(result[0], 1)
|
| 658 |
+
if num is S.NaN:
|
| 659 |
+
return fnan, None, prec, None
|
| 660 |
+
if num.is_infinite:
|
| 661 |
+
special.append(num)
|
| 662 |
+
if special:
|
| 663 |
+
if has_zero:
|
| 664 |
+
return fnan, None, prec, None
|
| 665 |
+
from .mul import Mul
|
| 666 |
+
return evalf(Mul(*special), prec + 4, {})
|
| 667 |
+
if has_zero:
|
| 668 |
+
return None, None, None, None
|
| 669 |
+
|
| 670 |
+
# With guard digits, multiplication in the real case does not destroy
|
| 671 |
+
# accuracy. This is also true in the complex case when considering the
|
| 672 |
+
# total accuracy; however accuracy for the real or imaginary parts
|
| 673 |
+
# separately may be lower.
|
| 674 |
+
acc = prec
|
| 675 |
+
|
| 676 |
+
# XXX: big overestimate
|
| 677 |
+
working_prec = prec + len(args) + 5
|
| 678 |
+
|
| 679 |
+
# Empty product is 1
|
| 680 |
+
start = man, exp, bc = MPZ(1), 0, 1
|
| 681 |
+
|
| 682 |
+
# First, we multiply all pure real or pure imaginary numbers.
|
| 683 |
+
# direction tells us that the result should be multiplied by
|
| 684 |
+
# I**direction; all other numbers get put into complex_factors
|
| 685 |
+
# to be multiplied out after the first phase.
|
| 686 |
+
last = len(args)
|
| 687 |
+
direction = 0
|
| 688 |
+
args.append(S.One)
|
| 689 |
+
complex_factors = []
|
| 690 |
+
|
| 691 |
+
for i, arg in enumerate(args):
|
| 692 |
+
if i != last and pure_complex(arg):
|
| 693 |
+
args[-1] = (args[-1]*arg).expand()
|
| 694 |
+
continue
|
| 695 |
+
elif i == last and arg is S.One:
|
| 696 |
+
continue
|
| 697 |
+
re, im, re_acc, im_acc = evalf(arg, working_prec, options)
|
| 698 |
+
if re and im:
|
| 699 |
+
complex_factors.append((re, im, re_acc, im_acc))
|
| 700 |
+
continue
|
| 701 |
+
elif re:
|
| 702 |
+
(s, m, e, b), w_acc = re, re_acc
|
| 703 |
+
elif im:
|
| 704 |
+
(s, m, e, b), w_acc = im, im_acc
|
| 705 |
+
direction += 1
|
| 706 |
+
else:
|
| 707 |
+
return None, None, None, None
|
| 708 |
+
direction += 2*s
|
| 709 |
+
man *= m
|
| 710 |
+
exp += e
|
| 711 |
+
bc += b
|
| 712 |
+
while bc > 3*working_prec:
|
| 713 |
+
man >>= working_prec
|
| 714 |
+
exp += working_prec
|
| 715 |
+
bc -= working_prec
|
| 716 |
+
acc = min(acc, w_acc)
|
| 717 |
+
sign = (direction & 2) >> 1
|
| 718 |
+
if not complex_factors:
|
| 719 |
+
v = normalize(sign, man, exp, bitcount(man), prec, rnd)
|
| 720 |
+
# multiply by i
|
| 721 |
+
if direction & 1:
|
| 722 |
+
return None, v, None, acc
|
| 723 |
+
else:
|
| 724 |
+
return v, None, acc, None
|
| 725 |
+
else:
|
| 726 |
+
# initialize with the first term
|
| 727 |
+
if (man, exp, bc) != start:
|
| 728 |
+
# there was a real part; give it an imaginary part
|
| 729 |
+
re, im = (sign, man, exp, bitcount(man)), (0, MPZ(0), 0, 0)
|
| 730 |
+
i0 = 0
|
| 731 |
+
else:
|
| 732 |
+
# there is no real part to start (other than the starting 1)
|
| 733 |
+
wre, wim, wre_acc, wim_acc = complex_factors[0]
|
| 734 |
+
acc = min(acc,
|
| 735 |
+
complex_accuracy((wre, wim, wre_acc, wim_acc)))
|
| 736 |
+
re = wre
|
| 737 |
+
im = wim
|
| 738 |
+
i0 = 1
|
| 739 |
+
|
| 740 |
+
for wre, wim, wre_acc, wim_acc in complex_factors[i0:]:
|
| 741 |
+
# acc is the overall accuracy of the product; we aren't
|
| 742 |
+
# computing exact accuracies of the product.
|
| 743 |
+
acc = min(acc,
|
| 744 |
+
complex_accuracy((wre, wim, wre_acc, wim_acc)))
|
| 745 |
+
|
| 746 |
+
use_prec = working_prec
|
| 747 |
+
A = mpf_mul(re, wre, use_prec)
|
| 748 |
+
B = mpf_mul(mpf_neg(im), wim, use_prec)
|
| 749 |
+
C = mpf_mul(re, wim, use_prec)
|
| 750 |
+
D = mpf_mul(im, wre, use_prec)
|
| 751 |
+
re = mpf_add(A, B, use_prec)
|
| 752 |
+
im = mpf_add(C, D, use_prec)
|
| 753 |
+
if options.get('verbose'):
|
| 754 |
+
print("MUL: wanted", prec, "accurate bits, got", acc)
|
| 755 |
+
# multiply by I
|
| 756 |
+
if direction & 1:
|
| 757 |
+
re, im = mpf_neg(im), re
|
| 758 |
+
return re, im, acc, acc
|
| 759 |
+
|
| 760 |
+
|
| 761 |
+
def evalf_pow(v: 'Pow', prec: int, options) -> TMP_RES:
|
| 762 |
+
|
| 763 |
+
target_prec = prec
|
| 764 |
+
base, exp = v.args
|
| 765 |
+
|
| 766 |
+
# We handle x**n separately. This has two purposes: 1) it is much
|
| 767 |
+
# faster, because we avoid calling evalf on the exponent, and 2) it
|
| 768 |
+
# allows better handling of real/imaginary parts that are exactly zero
|
| 769 |
+
if exp.is_Integer:
|
| 770 |
+
p: int = exp.p # type: ignore
|
| 771 |
+
# Exact
|
| 772 |
+
if not p:
|
| 773 |
+
return fone, None, prec, None
|
| 774 |
+
# Exponentiation by p magnifies relative error by |p|, so the
|
| 775 |
+
# base must be evaluated with increased precision if p is large
|
| 776 |
+
prec += int(math.log2(abs(p)))
|
| 777 |
+
result = evalf(base, prec + 5, options)
|
| 778 |
+
if result is S.ComplexInfinity:
|
| 779 |
+
if p < 0:
|
| 780 |
+
return None, None, None, None
|
| 781 |
+
return result
|
| 782 |
+
re, im, re_acc, im_acc = result
|
| 783 |
+
# Real to integer power
|
| 784 |
+
if re and not im:
|
| 785 |
+
return mpf_pow_int(re, p, target_prec), None, target_prec, None
|
| 786 |
+
# (x*I)**n = I**n * x**n
|
| 787 |
+
if im and not re:
|
| 788 |
+
z = mpf_pow_int(im, p, target_prec)
|
| 789 |
+
case = p % 4
|
| 790 |
+
if case == 0:
|
| 791 |
+
return z, None, target_prec, None
|
| 792 |
+
if case == 1:
|
| 793 |
+
return None, z, None, target_prec
|
| 794 |
+
if case == 2:
|
| 795 |
+
return mpf_neg(z), None, target_prec, None
|
| 796 |
+
if case == 3:
|
| 797 |
+
return None, mpf_neg(z), None, target_prec
|
| 798 |
+
# Zero raised to an integer power
|
| 799 |
+
if not re:
|
| 800 |
+
if p < 0:
|
| 801 |
+
return S.ComplexInfinity
|
| 802 |
+
return None, None, None, None
|
| 803 |
+
# General complex number to arbitrary integer power
|
| 804 |
+
re, im = libmp.mpc_pow_int((re, im), p, prec)
|
| 805 |
+
# Assumes full accuracy in input
|
| 806 |
+
return finalize_complex(re, im, target_prec)
|
| 807 |
+
|
| 808 |
+
result = evalf(base, prec + 5, options)
|
| 809 |
+
if result is S.ComplexInfinity:
|
| 810 |
+
if exp.is_Rational:
|
| 811 |
+
if exp < 0:
|
| 812 |
+
return None, None, None, None
|
| 813 |
+
return result
|
| 814 |
+
raise NotImplementedError
|
| 815 |
+
|
| 816 |
+
# Pure square root
|
| 817 |
+
if exp is S.Half:
|
| 818 |
+
xre, xim, _, _ = result
|
| 819 |
+
# General complex square root
|
| 820 |
+
if xim:
|
| 821 |
+
re, im = libmp.mpc_sqrt((xre or fzero, xim), prec)
|
| 822 |
+
return finalize_complex(re, im, prec)
|
| 823 |
+
if not xre:
|
| 824 |
+
return None, None, None, None
|
| 825 |
+
# Square root of a negative real number
|
| 826 |
+
if mpf_lt(xre, fzero):
|
| 827 |
+
return None, mpf_sqrt(mpf_neg(xre), prec), None, prec
|
| 828 |
+
# Positive square root
|
| 829 |
+
return mpf_sqrt(xre, prec), None, prec, None
|
| 830 |
+
|
| 831 |
+
# We first evaluate the exponent to find its magnitude
|
| 832 |
+
# This determines the working precision that must be used
|
| 833 |
+
prec += 10
|
| 834 |
+
result = evalf(exp, prec, options)
|
| 835 |
+
if result is S.ComplexInfinity:
|
| 836 |
+
return fnan, None, prec, None
|
| 837 |
+
yre, yim, _, _ = result
|
| 838 |
+
# Special cases: x**0
|
| 839 |
+
if not (yre or yim):
|
| 840 |
+
return fone, None, prec, None
|
| 841 |
+
|
| 842 |
+
ysize = fastlog(yre)
|
| 843 |
+
# Restart if too big
|
| 844 |
+
# XXX: prec + ysize might exceed maxprec
|
| 845 |
+
if ysize > 5:
|
| 846 |
+
prec += ysize
|
| 847 |
+
yre, yim, _, _ = evalf(exp, prec, options)
|
| 848 |
+
|
| 849 |
+
# Pure exponential function; no need to evalf the base
|
| 850 |
+
if base is S.Exp1:
|
| 851 |
+
if yim:
|
| 852 |
+
re, im = libmp.mpc_exp((yre or fzero, yim), prec)
|
| 853 |
+
return finalize_complex(re, im, target_prec)
|
| 854 |
+
return mpf_exp(yre, target_prec), None, target_prec, None
|
| 855 |
+
|
| 856 |
+
xre, xim, _, _ = evalf(base, prec + 5, options)
|
| 857 |
+
# 0**y
|
| 858 |
+
if not (xre or xim):
|
| 859 |
+
if yim:
|
| 860 |
+
return fnan, None, prec, None
|
| 861 |
+
if yre[0] == 1: # y < 0
|
| 862 |
+
return S.ComplexInfinity
|
| 863 |
+
return None, None, None, None
|
| 864 |
+
|
| 865 |
+
# (real ** complex) or (complex ** complex)
|
| 866 |
+
if yim:
|
| 867 |
+
re, im = libmp.mpc_pow(
|
| 868 |
+
(xre or fzero, xim or fzero), (yre or fzero, yim),
|
| 869 |
+
target_prec)
|
| 870 |
+
return finalize_complex(re, im, target_prec)
|
| 871 |
+
# complex ** real
|
| 872 |
+
if xim:
|
| 873 |
+
re, im = libmp.mpc_pow_mpf((xre or fzero, xim), yre, target_prec)
|
| 874 |
+
return finalize_complex(re, im, target_prec)
|
| 875 |
+
# negative ** real
|
| 876 |
+
elif mpf_lt(xre, fzero):
|
| 877 |
+
re, im = libmp.mpc_pow_mpf((xre, fzero), yre, target_prec)
|
| 878 |
+
return finalize_complex(re, im, target_prec)
|
| 879 |
+
# positive ** real
|
| 880 |
+
else:
|
| 881 |
+
return mpf_pow(xre, yre, target_prec), None, target_prec, None
|
| 882 |
+
|
| 883 |
+
|
| 884 |
+
#----------------------------------------------------------------------------#
|
| 885 |
+
# #
|
| 886 |
+
# Special functions #
|
| 887 |
+
# #
|
| 888 |
+
#----------------------------------------------------------------------------#
|
| 889 |
+
|
| 890 |
+
|
| 891 |
+
def evalf_exp(expr: 'exp', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 892 |
+
from .power import Pow
|
| 893 |
+
return evalf_pow(Pow(S.Exp1, expr.exp, evaluate=False), prec, options)
|
| 894 |
+
|
| 895 |
+
|
| 896 |
+
def evalf_trig(v: 'Expr', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 897 |
+
"""
|
| 898 |
+
This function handles sin and cos of complex arguments.
|
| 899 |
+
|
| 900 |
+
TODO: should also handle tan of complex arguments.
|
| 901 |
+
"""
|
| 902 |
+
from sympy.functions.elementary.trigonometric import cos, sin
|
| 903 |
+
if isinstance(v, cos):
|
| 904 |
+
func = mpf_cos
|
| 905 |
+
elif isinstance(v, sin):
|
| 906 |
+
func = mpf_sin
|
| 907 |
+
else:
|
| 908 |
+
raise NotImplementedError
|
| 909 |
+
arg = v.args[0]
|
| 910 |
+
# 20 extra bits is possibly overkill. It does make the need
|
| 911 |
+
# to restart very unlikely
|
| 912 |
+
xprec = prec + 20
|
| 913 |
+
re, im, re_acc, im_acc = evalf(arg, xprec, options)
|
| 914 |
+
if im:
|
| 915 |
+
if 'subs' in options:
|
| 916 |
+
v = v.subs(options['subs'])
|
| 917 |
+
return evalf(v._eval_evalf(prec), prec, options)
|
| 918 |
+
if not re:
|
| 919 |
+
if isinstance(v, cos):
|
| 920 |
+
return fone, None, prec, None
|
| 921 |
+
elif isinstance(v, sin):
|
| 922 |
+
return None, None, None, None
|
| 923 |
+
else:
|
| 924 |
+
raise NotImplementedError
|
| 925 |
+
# For trigonometric functions, we are interested in the
|
| 926 |
+
# fixed-point (absolute) accuracy of the argument.
|
| 927 |
+
xsize = fastlog(re)
|
| 928 |
+
# Magnitude <= 1.0. OK to compute directly, because there is no
|
| 929 |
+
# danger of hitting the first root of cos (with sin, magnitude
|
| 930 |
+
# <= 2.0 would actually be ok)
|
| 931 |
+
if xsize < 1:
|
| 932 |
+
return func(re, prec, rnd), None, prec, None
|
| 933 |
+
# Very large
|
| 934 |
+
if xsize >= 10:
|
| 935 |
+
xprec = prec + xsize
|
| 936 |
+
re, im, re_acc, im_acc = evalf(arg, xprec, options)
|
| 937 |
+
# Need to repeat in case the argument is very close to a
|
| 938 |
+
# multiple of pi (or pi/2), hitting close to a root
|
| 939 |
+
while 1:
|
| 940 |
+
y = func(re, prec, rnd)
|
| 941 |
+
ysize = fastlog(y)
|
| 942 |
+
gap = -ysize
|
| 943 |
+
accuracy = (xprec - xsize) - gap
|
| 944 |
+
if accuracy < prec:
|
| 945 |
+
if options.get('verbose'):
|
| 946 |
+
print("SIN/COS", accuracy, "wanted", prec, "gap", gap)
|
| 947 |
+
print(to_str(y, 10))
|
| 948 |
+
if xprec > options.get('maxprec', DEFAULT_MAXPREC):
|
| 949 |
+
return y, None, accuracy, None
|
| 950 |
+
xprec += gap
|
| 951 |
+
re, im, re_acc, im_acc = evalf(arg, xprec, options)
|
| 952 |
+
continue
|
| 953 |
+
else:
|
| 954 |
+
return y, None, prec, None
|
| 955 |
+
|
| 956 |
+
|
| 957 |
+
def evalf_log(expr: 'log', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 958 |
+
if len(expr.args)>1:
|
| 959 |
+
expr = expr.doit()
|
| 960 |
+
return evalf(expr, prec, options)
|
| 961 |
+
arg = expr.args[0]
|
| 962 |
+
workprec = prec + 10
|
| 963 |
+
result = evalf(arg, workprec, options)
|
| 964 |
+
if result is S.ComplexInfinity:
|
| 965 |
+
return result
|
| 966 |
+
xre, xim, xacc, _ = result
|
| 967 |
+
|
| 968 |
+
# evalf can return NoneTypes if chop=True
|
| 969 |
+
# issue 18516, 19623
|
| 970 |
+
if xre is xim is None:
|
| 971 |
+
# Dear reviewer, I do not know what -inf is;
|
| 972 |
+
# it looks to be (1, 0, -789, -3)
|
| 973 |
+
# but I'm not sure in general,
|
| 974 |
+
# so we just let mpmath figure
|
| 975 |
+
# it out by taking log of 0 directly.
|
| 976 |
+
# It would be better to return -inf instead.
|
| 977 |
+
xre = fzero
|
| 978 |
+
|
| 979 |
+
if xim:
|
| 980 |
+
from sympy.functions.elementary.complexes import Abs
|
| 981 |
+
from sympy.functions.elementary.exponential import log
|
| 982 |
+
|
| 983 |
+
# XXX: use get_abs etc instead
|
| 984 |
+
re = evalf_log(
|
| 985 |
+
log(Abs(arg, evaluate=False), evaluate=False), prec, options)
|
| 986 |
+
im = mpf_atan2(xim, xre or fzero, prec)
|
| 987 |
+
return re[0], im, re[2], prec
|
| 988 |
+
|
| 989 |
+
imaginary_term = (mpf_cmp(xre, fzero) < 0)
|
| 990 |
+
|
| 991 |
+
re = mpf_log(mpf_abs(xre), prec, rnd)
|
| 992 |
+
size = fastlog(re)
|
| 993 |
+
if prec - size > workprec and re != fzero:
|
| 994 |
+
from .add import Add
|
| 995 |
+
# We actually need to compute 1+x accurately, not x
|
| 996 |
+
add = Add(S.NegativeOne, arg, evaluate=False)
|
| 997 |
+
xre, xim, _, _ = evalf_add(add, prec, options)
|
| 998 |
+
prec2 = workprec - fastlog(xre)
|
| 999 |
+
# xre is now x - 1 so we add 1 back here to calculate x
|
| 1000 |
+
re = mpf_log(mpf_abs(mpf_add(xre, fone, prec2)), prec, rnd)
|
| 1001 |
+
|
| 1002 |
+
re_acc = prec
|
| 1003 |
+
|
| 1004 |
+
if imaginary_term:
|
| 1005 |
+
return re, mpf_pi(prec), re_acc, prec
|
| 1006 |
+
else:
|
| 1007 |
+
return re, None, re_acc, None
|
| 1008 |
+
|
| 1009 |
+
|
| 1010 |
+
def evalf_atan(v: 'atan', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1011 |
+
arg = v.args[0]
|
| 1012 |
+
xre, xim, reacc, imacc = evalf(arg, prec + 5, options)
|
| 1013 |
+
if xre is xim is None:
|
| 1014 |
+
return (None,)*4
|
| 1015 |
+
if xim:
|
| 1016 |
+
raise NotImplementedError
|
| 1017 |
+
return mpf_atan(xre, prec, rnd), None, prec, None
|
| 1018 |
+
|
| 1019 |
+
|
| 1020 |
+
def evalf_subs(prec: int, subs: dict) -> dict:
|
| 1021 |
+
""" Change all Float entries in `subs` to have precision prec. """
|
| 1022 |
+
newsubs = {}
|
| 1023 |
+
for a, b in subs.items():
|
| 1024 |
+
b = S(b)
|
| 1025 |
+
if b.is_Float:
|
| 1026 |
+
b = b._eval_evalf(prec)
|
| 1027 |
+
newsubs[a] = b
|
| 1028 |
+
return newsubs
|
| 1029 |
+
|
| 1030 |
+
|
| 1031 |
+
def evalf_piecewise(expr: 'Expr', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1032 |
+
from .numbers import Float, Integer
|
| 1033 |
+
if 'subs' in options:
|
| 1034 |
+
expr = expr.subs(evalf_subs(prec, options['subs']))
|
| 1035 |
+
newopts = options.copy()
|
| 1036 |
+
del newopts['subs']
|
| 1037 |
+
if hasattr(expr, 'func'):
|
| 1038 |
+
return evalf(expr, prec, newopts)
|
| 1039 |
+
if isinstance(expr, float):
|
| 1040 |
+
return evalf(Float(expr), prec, newopts)
|
| 1041 |
+
if isinstance(expr, int):
|
| 1042 |
+
return evalf(Integer(expr), prec, newopts)
|
| 1043 |
+
|
| 1044 |
+
# We still have undefined symbols
|
| 1045 |
+
raise NotImplementedError
|
| 1046 |
+
|
| 1047 |
+
|
| 1048 |
+
def evalf_alg_num(a: 'AlgebraicNumber', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1049 |
+
return evalf(a.to_root(), prec, options)
|
| 1050 |
+
|
| 1051 |
+
#----------------------------------------------------------------------------#
|
| 1052 |
+
# #
|
| 1053 |
+
# High-level operations #
|
| 1054 |
+
# #
|
| 1055 |
+
#----------------------------------------------------------------------------#
|
| 1056 |
+
|
| 1057 |
+
|
| 1058 |
+
def as_mpmath(x: Any, prec: int, options: OPT_DICT) -> tUnion[mpc, mpf]:
|
| 1059 |
+
from .numbers import Infinity, NegativeInfinity, Zero
|
| 1060 |
+
x = sympify(x)
|
| 1061 |
+
if isinstance(x, Zero) or x == 0.0:
|
| 1062 |
+
return mpf(0)
|
| 1063 |
+
if isinstance(x, Infinity):
|
| 1064 |
+
return mpf('inf')
|
| 1065 |
+
if isinstance(x, NegativeInfinity):
|
| 1066 |
+
return mpf('-inf')
|
| 1067 |
+
# XXX
|
| 1068 |
+
result = evalf(x, prec, options)
|
| 1069 |
+
return quad_to_mpmath(result)
|
| 1070 |
+
|
| 1071 |
+
|
| 1072 |
+
def do_integral(expr: 'Integral', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1073 |
+
func = expr.args[0]
|
| 1074 |
+
x, xlow, xhigh = expr.args[1]
|
| 1075 |
+
if xlow == xhigh:
|
| 1076 |
+
xlow = xhigh = 0
|
| 1077 |
+
elif x not in func.free_symbols:
|
| 1078 |
+
# only the difference in limits matters in this case
|
| 1079 |
+
# so if there is a symbol in common that will cancel
|
| 1080 |
+
# out when taking the difference, then use that
|
| 1081 |
+
# difference
|
| 1082 |
+
if xhigh.free_symbols & xlow.free_symbols:
|
| 1083 |
+
diff = xhigh - xlow
|
| 1084 |
+
if diff.is_number:
|
| 1085 |
+
xlow, xhigh = 0, diff
|
| 1086 |
+
|
| 1087 |
+
oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC)
|
| 1088 |
+
options['maxprec'] = min(oldmaxprec, 2*prec)
|
| 1089 |
+
|
| 1090 |
+
with workprec(prec + 5):
|
| 1091 |
+
xlow = as_mpmath(xlow, prec + 15, options)
|
| 1092 |
+
xhigh = as_mpmath(xhigh, prec + 15, options)
|
| 1093 |
+
|
| 1094 |
+
# Integration is like summation, and we can phone home from
|
| 1095 |
+
# the integrand function to update accuracy summation style
|
| 1096 |
+
# Note that this accuracy is inaccurate, since it fails
|
| 1097 |
+
# to account for the variable quadrature weights,
|
| 1098 |
+
# but it is better than nothing
|
| 1099 |
+
|
| 1100 |
+
from sympy.functions.elementary.trigonometric import cos, sin
|
| 1101 |
+
from .symbol import Wild
|
| 1102 |
+
|
| 1103 |
+
have_part = [False, False]
|
| 1104 |
+
max_real_term: tUnion[float, int] = MINUS_INF
|
| 1105 |
+
max_imag_term: tUnion[float, int] = MINUS_INF
|
| 1106 |
+
|
| 1107 |
+
def f(t: 'Expr') -> tUnion[mpc, mpf]:
|
| 1108 |
+
nonlocal max_real_term, max_imag_term
|
| 1109 |
+
re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}})
|
| 1110 |
+
|
| 1111 |
+
have_part[0] = re or have_part[0]
|
| 1112 |
+
have_part[1] = im or have_part[1]
|
| 1113 |
+
|
| 1114 |
+
max_real_term = max(max_real_term, fastlog(re))
|
| 1115 |
+
max_imag_term = max(max_imag_term, fastlog(im))
|
| 1116 |
+
|
| 1117 |
+
if im:
|
| 1118 |
+
return mpc(re or fzero, im)
|
| 1119 |
+
return mpf(re or fzero)
|
| 1120 |
+
|
| 1121 |
+
if options.get('quad') == 'osc':
|
| 1122 |
+
A = Wild('A', exclude=[x])
|
| 1123 |
+
B = Wild('B', exclude=[x])
|
| 1124 |
+
D = Wild('D')
|
| 1125 |
+
m = func.match(cos(A*x + B)*D)
|
| 1126 |
+
if not m:
|
| 1127 |
+
m = func.match(sin(A*x + B)*D)
|
| 1128 |
+
if not m:
|
| 1129 |
+
raise ValueError("An integrand of the form sin(A*x+B)*f(x) "
|
| 1130 |
+
"or cos(A*x+B)*f(x) is required for oscillatory quadrature")
|
| 1131 |
+
period = as_mpmath(2*S.Pi/m[A], prec + 15, options)
|
| 1132 |
+
result = quadosc(f, [xlow, xhigh], period=period)
|
| 1133 |
+
# XXX: quadosc does not do error detection yet
|
| 1134 |
+
quadrature_error = MINUS_INF
|
| 1135 |
+
else:
|
| 1136 |
+
result, quadrature_err = quadts(f, [xlow, xhigh], error=1)
|
| 1137 |
+
quadrature_error = fastlog(quadrature_err._mpf_)
|
| 1138 |
+
|
| 1139 |
+
options['maxprec'] = oldmaxprec
|
| 1140 |
+
|
| 1141 |
+
if have_part[0]:
|
| 1142 |
+
re: Optional[MPF_TUP] = result.real._mpf_
|
| 1143 |
+
re_acc: Optional[int]
|
| 1144 |
+
if re == fzero:
|
| 1145 |
+
re_s, re_acc = scaled_zero(int(-max(prec, max_real_term, quadrature_error)))
|
| 1146 |
+
re = scaled_zero(re_s) # handled ok in evalf_integral
|
| 1147 |
+
else:
|
| 1148 |
+
re_acc = int(-max(max_real_term - fastlog(re) - prec, quadrature_error))
|
| 1149 |
+
else:
|
| 1150 |
+
re, re_acc = None, None
|
| 1151 |
+
|
| 1152 |
+
if have_part[1]:
|
| 1153 |
+
im: Optional[MPF_TUP] = result.imag._mpf_
|
| 1154 |
+
im_acc: Optional[int]
|
| 1155 |
+
if im == fzero:
|
| 1156 |
+
im_s, im_acc = scaled_zero(int(-max(prec, max_imag_term, quadrature_error)))
|
| 1157 |
+
im = scaled_zero(im_s) # handled ok in evalf_integral
|
| 1158 |
+
else:
|
| 1159 |
+
im_acc = int(-max(max_imag_term - fastlog(im) - prec, quadrature_error))
|
| 1160 |
+
else:
|
| 1161 |
+
im, im_acc = None, None
|
| 1162 |
+
|
| 1163 |
+
result = re, im, re_acc, im_acc
|
| 1164 |
+
return result
|
| 1165 |
+
|
| 1166 |
+
|
| 1167 |
+
def evalf_integral(expr: 'Integral', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1168 |
+
limits = expr.limits
|
| 1169 |
+
if len(limits) != 1 or len(limits[0]) != 3:
|
| 1170 |
+
raise NotImplementedError
|
| 1171 |
+
workprec = prec
|
| 1172 |
+
i = 0
|
| 1173 |
+
maxprec = options.get('maxprec', INF)
|
| 1174 |
+
while 1:
|
| 1175 |
+
result = do_integral(expr, workprec, options)
|
| 1176 |
+
accuracy = complex_accuracy(result)
|
| 1177 |
+
if accuracy >= prec: # achieved desired precision
|
| 1178 |
+
break
|
| 1179 |
+
if workprec >= maxprec: # can't increase accuracy any more
|
| 1180 |
+
break
|
| 1181 |
+
if accuracy == -1:
|
| 1182 |
+
# maybe the answer really is zero and maybe we just haven't increased
|
| 1183 |
+
# the precision enough. So increase by doubling to not take too long
|
| 1184 |
+
# to get to maxprec.
|
| 1185 |
+
workprec *= 2
|
| 1186 |
+
else:
|
| 1187 |
+
workprec += max(prec, 2**i)
|
| 1188 |
+
workprec = min(workprec, maxprec)
|
| 1189 |
+
i += 1
|
| 1190 |
+
return result
|
| 1191 |
+
|
| 1192 |
+
|
| 1193 |
+
def check_convergence(numer: 'Expr', denom: 'Expr', n: 'Symbol') -> tTuple[int, Any, Any]:
|
| 1194 |
+
"""
|
| 1195 |
+
Returns
|
| 1196 |
+
=======
|
| 1197 |
+
|
| 1198 |
+
(h, g, p) where
|
| 1199 |
+
-- h is:
|
| 1200 |
+
> 0 for convergence of rate 1/factorial(n)**h
|
| 1201 |
+
< 0 for divergence of rate factorial(n)**(-h)
|
| 1202 |
+
= 0 for geometric or polynomial convergence or divergence
|
| 1203 |
+
|
| 1204 |
+
-- abs(g) is:
|
| 1205 |
+
> 1 for geometric convergence of rate 1/h**n
|
| 1206 |
+
< 1 for geometric divergence of rate h**n
|
| 1207 |
+
= 1 for polynomial convergence or divergence
|
| 1208 |
+
|
| 1209 |
+
(g < 0 indicates an alternating series)
|
| 1210 |
+
|
| 1211 |
+
-- p is:
|
| 1212 |
+
> 1 for polynomial convergence of rate 1/n**h
|
| 1213 |
+
<= 1 for polynomial divergence of rate n**(-h)
|
| 1214 |
+
|
| 1215 |
+
"""
|
| 1216 |
+
from sympy.polys.polytools import Poly
|
| 1217 |
+
npol = Poly(numer, n)
|
| 1218 |
+
dpol = Poly(denom, n)
|
| 1219 |
+
p = npol.degree()
|
| 1220 |
+
q = dpol.degree()
|
| 1221 |
+
rate = q - p
|
| 1222 |
+
if rate:
|
| 1223 |
+
return rate, None, None
|
| 1224 |
+
constant = dpol.LC() / npol.LC()
|
| 1225 |
+
from .numbers import equal_valued
|
| 1226 |
+
if not equal_valued(abs(constant), 1):
|
| 1227 |
+
return rate, constant, None
|
| 1228 |
+
if npol.degree() == dpol.degree() == 0:
|
| 1229 |
+
return rate, constant, 0
|
| 1230 |
+
pc = npol.all_coeffs()[1]
|
| 1231 |
+
qc = dpol.all_coeffs()[1]
|
| 1232 |
+
return rate, constant, (qc - pc)/dpol.LC()
|
| 1233 |
+
|
| 1234 |
+
|
| 1235 |
+
def hypsum(expr: 'Expr', n: 'Symbol', start: int, prec: int) -> mpf:
|
| 1236 |
+
"""
|
| 1237 |
+
Sum a rapidly convergent infinite hypergeometric series with
|
| 1238 |
+
given general term, e.g. e = hypsum(1/factorial(n), n). The
|
| 1239 |
+
quotient between successive terms must be a quotient of integer
|
| 1240 |
+
polynomials.
|
| 1241 |
+
"""
|
| 1242 |
+
from .numbers import Float, equal_valued
|
| 1243 |
+
from sympy.simplify.simplify import hypersimp
|
| 1244 |
+
|
| 1245 |
+
if prec == float('inf'):
|
| 1246 |
+
raise NotImplementedError('does not support inf prec')
|
| 1247 |
+
|
| 1248 |
+
if start:
|
| 1249 |
+
expr = expr.subs(n, n + start)
|
| 1250 |
+
hs = hypersimp(expr, n)
|
| 1251 |
+
if hs is None:
|
| 1252 |
+
raise NotImplementedError("a hypergeometric series is required")
|
| 1253 |
+
num, den = hs.as_numer_denom()
|
| 1254 |
+
|
| 1255 |
+
func1 = lambdify(n, num)
|
| 1256 |
+
func2 = lambdify(n, den)
|
| 1257 |
+
|
| 1258 |
+
h, g, p = check_convergence(num, den, n)
|
| 1259 |
+
|
| 1260 |
+
if h < 0:
|
| 1261 |
+
raise ValueError("Sum diverges like (n!)^%i" % (-h))
|
| 1262 |
+
|
| 1263 |
+
term = expr.subs(n, 0)
|
| 1264 |
+
if not term.is_Rational:
|
| 1265 |
+
raise NotImplementedError("Non rational term functionality is not implemented.")
|
| 1266 |
+
|
| 1267 |
+
# Direct summation if geometric or faster
|
| 1268 |
+
if h > 0 or (h == 0 and abs(g) > 1):
|
| 1269 |
+
term = (MPZ(term.p) << prec) // term.q
|
| 1270 |
+
s = term
|
| 1271 |
+
k = 1
|
| 1272 |
+
while abs(term) > 5:
|
| 1273 |
+
term *= MPZ(func1(k - 1))
|
| 1274 |
+
term //= MPZ(func2(k - 1))
|
| 1275 |
+
s += term
|
| 1276 |
+
k += 1
|
| 1277 |
+
return from_man_exp(s, -prec)
|
| 1278 |
+
else:
|
| 1279 |
+
alt = g < 0
|
| 1280 |
+
if abs(g) < 1:
|
| 1281 |
+
raise ValueError("Sum diverges like (%i)^n" % abs(1/g))
|
| 1282 |
+
if p < 1 or (equal_valued(p, 1) and not alt):
|
| 1283 |
+
raise ValueError("Sum diverges like n^%i" % (-p))
|
| 1284 |
+
# We have polynomial convergence: use Richardson extrapolation
|
| 1285 |
+
vold = None
|
| 1286 |
+
ndig = prec_to_dps(prec)
|
| 1287 |
+
while True:
|
| 1288 |
+
# Need to use at least quad precision because a lot of cancellation
|
| 1289 |
+
# might occur in the extrapolation process; we check the answer to
|
| 1290 |
+
# make sure that the desired precision has been reached, too.
|
| 1291 |
+
prec2 = 4*prec
|
| 1292 |
+
term0 = (MPZ(term.p) << prec2) // term.q
|
| 1293 |
+
|
| 1294 |
+
def summand(k, _term=[term0]):
|
| 1295 |
+
if k:
|
| 1296 |
+
k = int(k)
|
| 1297 |
+
_term[0] *= MPZ(func1(k - 1))
|
| 1298 |
+
_term[0] //= MPZ(func2(k - 1))
|
| 1299 |
+
return make_mpf(from_man_exp(_term[0], -prec2))
|
| 1300 |
+
|
| 1301 |
+
with workprec(prec):
|
| 1302 |
+
v = nsum(summand, [0, mpmath_inf], method='richardson')
|
| 1303 |
+
vf = Float(v, ndig)
|
| 1304 |
+
if vold is not None and vold == vf:
|
| 1305 |
+
break
|
| 1306 |
+
prec += prec # double precision each time
|
| 1307 |
+
vold = vf
|
| 1308 |
+
|
| 1309 |
+
return v._mpf_
|
| 1310 |
+
|
| 1311 |
+
|
| 1312 |
+
def evalf_prod(expr: 'Product', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1313 |
+
if all((l[1] - l[2]).is_Integer for l in expr.limits):
|
| 1314 |
+
result = evalf(expr.doit(), prec=prec, options=options)
|
| 1315 |
+
else:
|
| 1316 |
+
from sympy.concrete.summations import Sum
|
| 1317 |
+
result = evalf(expr.rewrite(Sum), prec=prec, options=options)
|
| 1318 |
+
return result
|
| 1319 |
+
|
| 1320 |
+
|
| 1321 |
+
def evalf_sum(expr: 'Sum', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1322 |
+
from .numbers import Float
|
| 1323 |
+
if 'subs' in options:
|
| 1324 |
+
expr = expr.subs(options['subs'])
|
| 1325 |
+
func = expr.function
|
| 1326 |
+
limits = expr.limits
|
| 1327 |
+
if len(limits) != 1 or len(limits[0]) != 3:
|
| 1328 |
+
raise NotImplementedError
|
| 1329 |
+
if func.is_zero:
|
| 1330 |
+
return None, None, prec, None
|
| 1331 |
+
prec2 = prec + 10
|
| 1332 |
+
try:
|
| 1333 |
+
n, a, b = limits[0]
|
| 1334 |
+
if b is not S.Infinity or a is S.NegativeInfinity or a != int(a):
|
| 1335 |
+
raise NotImplementedError
|
| 1336 |
+
# Use fast hypergeometric summation if possible
|
| 1337 |
+
v = hypsum(func, n, int(a), prec2)
|
| 1338 |
+
delta = prec - fastlog(v)
|
| 1339 |
+
if fastlog(v) < -10:
|
| 1340 |
+
v = hypsum(func, n, int(a), delta)
|
| 1341 |
+
return v, None, min(prec, delta), None
|
| 1342 |
+
except NotImplementedError:
|
| 1343 |
+
# Euler-Maclaurin summation for general series
|
| 1344 |
+
eps = Float(2.0)**(-prec)
|
| 1345 |
+
for i in range(1, 5):
|
| 1346 |
+
m = n = 2**i * prec
|
| 1347 |
+
s, err = expr.euler_maclaurin(m=m, n=n, eps=eps,
|
| 1348 |
+
eval_integral=False)
|
| 1349 |
+
err = err.evalf()
|
| 1350 |
+
if err is S.NaN:
|
| 1351 |
+
raise NotImplementedError
|
| 1352 |
+
if err <= eps:
|
| 1353 |
+
break
|
| 1354 |
+
err = fastlog(evalf(abs(err), 20, options)[0])
|
| 1355 |
+
re, im, re_acc, im_acc = evalf(s, prec2, options)
|
| 1356 |
+
if re_acc is None:
|
| 1357 |
+
re_acc = -err
|
| 1358 |
+
if im_acc is None:
|
| 1359 |
+
im_acc = -err
|
| 1360 |
+
return re, im, re_acc, im_acc
|
| 1361 |
+
|
| 1362 |
+
|
| 1363 |
+
#----------------------------------------------------------------------------#
|
| 1364 |
+
# #
|
| 1365 |
+
# Symbolic interface #
|
| 1366 |
+
# #
|
| 1367 |
+
#----------------------------------------------------------------------------#
|
| 1368 |
+
|
| 1369 |
+
def evalf_symbol(x: 'Expr', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1370 |
+
val = options['subs'][x]
|
| 1371 |
+
if isinstance(val, mpf):
|
| 1372 |
+
if not val:
|
| 1373 |
+
return None, None, None, None
|
| 1374 |
+
return val._mpf_, None, prec, None
|
| 1375 |
+
else:
|
| 1376 |
+
if '_cache' not in options:
|
| 1377 |
+
options['_cache'] = {}
|
| 1378 |
+
cache = options['_cache']
|
| 1379 |
+
cached, cached_prec = cache.get(x, (None, MINUS_INF))
|
| 1380 |
+
if cached_prec >= prec:
|
| 1381 |
+
return cached
|
| 1382 |
+
v = evalf(sympify(val), prec, options)
|
| 1383 |
+
cache[x] = (v, prec)
|
| 1384 |
+
return v
|
| 1385 |
+
|
| 1386 |
+
|
| 1387 |
+
evalf_table: tDict[Type['Expr'], Callable[['Expr', int, OPT_DICT], TMP_RES]] = {}
|
| 1388 |
+
|
| 1389 |
+
|
| 1390 |
+
def _create_evalf_table():
|
| 1391 |
+
global evalf_table
|
| 1392 |
+
from sympy.concrete.products import Product
|
| 1393 |
+
from sympy.concrete.summations import Sum
|
| 1394 |
+
from .add import Add
|
| 1395 |
+
from .mul import Mul
|
| 1396 |
+
from .numbers import Exp1, Float, Half, ImaginaryUnit, Integer, NaN, NegativeOne, One, Pi, Rational, \
|
| 1397 |
+
Zero, ComplexInfinity, AlgebraicNumber
|
| 1398 |
+
from .power import Pow
|
| 1399 |
+
from .symbol import Dummy, Symbol
|
| 1400 |
+
from sympy.functions.elementary.complexes import Abs, im, re
|
| 1401 |
+
from sympy.functions.elementary.exponential import exp, log
|
| 1402 |
+
from sympy.functions.elementary.integers import ceiling, floor
|
| 1403 |
+
from sympy.functions.elementary.piecewise import Piecewise
|
| 1404 |
+
from sympy.functions.elementary.trigonometric import atan, cos, sin
|
| 1405 |
+
from sympy.integrals.integrals import Integral
|
| 1406 |
+
evalf_table = {
|
| 1407 |
+
Symbol: evalf_symbol,
|
| 1408 |
+
Dummy: evalf_symbol,
|
| 1409 |
+
Float: evalf_float,
|
| 1410 |
+
Rational: evalf_rational,
|
| 1411 |
+
Integer: evalf_integer,
|
| 1412 |
+
Zero: lambda x, prec, options: (None, None, prec, None),
|
| 1413 |
+
One: lambda x, prec, options: (fone, None, prec, None),
|
| 1414 |
+
Half: lambda x, prec, options: (fhalf, None, prec, None),
|
| 1415 |
+
Pi: lambda x, prec, options: (mpf_pi(prec), None, prec, None),
|
| 1416 |
+
Exp1: lambda x, prec, options: (mpf_e(prec), None, prec, None),
|
| 1417 |
+
ImaginaryUnit: lambda x, prec, options: (None, fone, None, prec),
|
| 1418 |
+
NegativeOne: lambda x, prec, options: (fnone, None, prec, None),
|
| 1419 |
+
ComplexInfinity: lambda x, prec, options: S.ComplexInfinity,
|
| 1420 |
+
NaN: lambda x, prec, options: (fnan, None, prec, None),
|
| 1421 |
+
|
| 1422 |
+
exp: evalf_exp,
|
| 1423 |
+
|
| 1424 |
+
cos: evalf_trig,
|
| 1425 |
+
sin: evalf_trig,
|
| 1426 |
+
|
| 1427 |
+
Add: evalf_add,
|
| 1428 |
+
Mul: evalf_mul,
|
| 1429 |
+
Pow: evalf_pow,
|
| 1430 |
+
|
| 1431 |
+
log: evalf_log,
|
| 1432 |
+
atan: evalf_atan,
|
| 1433 |
+
Abs: evalf_abs,
|
| 1434 |
+
|
| 1435 |
+
re: evalf_re,
|
| 1436 |
+
im: evalf_im,
|
| 1437 |
+
floor: evalf_floor,
|
| 1438 |
+
ceiling: evalf_ceiling,
|
| 1439 |
+
|
| 1440 |
+
Integral: evalf_integral,
|
| 1441 |
+
Sum: evalf_sum,
|
| 1442 |
+
Product: evalf_prod,
|
| 1443 |
+
Piecewise: evalf_piecewise,
|
| 1444 |
+
|
| 1445 |
+
AlgebraicNumber: evalf_alg_num,
|
| 1446 |
+
}
|
| 1447 |
+
|
| 1448 |
+
|
| 1449 |
+
def evalf(x: 'Expr', prec: int, options: OPT_DICT) -> TMP_RES:
|
| 1450 |
+
"""
|
| 1451 |
+
Evaluate the ``Expr`` instance, ``x``
|
| 1452 |
+
to a binary precision of ``prec``. This
|
| 1453 |
+
function is supposed to be used internally.
|
| 1454 |
+
|
| 1455 |
+
Parameters
|
| 1456 |
+
==========
|
| 1457 |
+
|
| 1458 |
+
x : Expr
|
| 1459 |
+
The formula to evaluate to a float.
|
| 1460 |
+
prec : int
|
| 1461 |
+
The binary precision that the output should have.
|
| 1462 |
+
options : dict
|
| 1463 |
+
A dictionary with the same entries as
|
| 1464 |
+
``EvalfMixin.evalf`` and in addition,
|
| 1465 |
+
``maxprec`` which is the maximum working precision.
|
| 1466 |
+
|
| 1467 |
+
Returns
|
| 1468 |
+
=======
|
| 1469 |
+
|
| 1470 |
+
An optional tuple, ``(re, im, re_acc, im_acc)``
|
| 1471 |
+
which are the real, imaginary, real accuracy
|
| 1472 |
+
and imaginary accuracy respectively. ``re`` is
|
| 1473 |
+
an mpf value tuple and so is ``im``. ``re_acc``
|
| 1474 |
+
and ``im_acc`` are ints.
|
| 1475 |
+
|
| 1476 |
+
NB: all these return values can be ``None``.
|
| 1477 |
+
If all values are ``None``, then that represents 0.
|
| 1478 |
+
Note that 0 is also represented as ``fzero = (0, 0, 0, 0)``.
|
| 1479 |
+
"""
|
| 1480 |
+
from sympy.functions.elementary.complexes import re as re_, im as im_
|
| 1481 |
+
try:
|
| 1482 |
+
rf = evalf_table[type(x)]
|
| 1483 |
+
r = rf(x, prec, options)
|
| 1484 |
+
except KeyError:
|
| 1485 |
+
# Fall back to ordinary evalf if possible
|
| 1486 |
+
if 'subs' in options:
|
| 1487 |
+
x = x.subs(evalf_subs(prec, options['subs']))
|
| 1488 |
+
xe = x._eval_evalf(prec)
|
| 1489 |
+
if xe is None:
|
| 1490 |
+
raise NotImplementedError
|
| 1491 |
+
as_real_imag = getattr(xe, "as_real_imag", None)
|
| 1492 |
+
if as_real_imag is None:
|
| 1493 |
+
raise NotImplementedError # e.g. FiniteSet(-1.0, 1.0).evalf()
|
| 1494 |
+
re, im = as_real_imag()
|
| 1495 |
+
if re.has(re_) or im.has(im_):
|
| 1496 |
+
raise NotImplementedError
|
| 1497 |
+
if re == 0.0:
|
| 1498 |
+
re = None
|
| 1499 |
+
reprec = None
|
| 1500 |
+
elif re.is_number:
|
| 1501 |
+
re = re._to_mpmath(prec, allow_ints=False)._mpf_
|
| 1502 |
+
reprec = prec
|
| 1503 |
+
else:
|
| 1504 |
+
raise NotImplementedError
|
| 1505 |
+
if im == 0.0:
|
| 1506 |
+
im = None
|
| 1507 |
+
imprec = None
|
| 1508 |
+
elif im.is_number:
|
| 1509 |
+
im = im._to_mpmath(prec, allow_ints=False)._mpf_
|
| 1510 |
+
imprec = prec
|
| 1511 |
+
else:
|
| 1512 |
+
raise NotImplementedError
|
| 1513 |
+
r = re, im, reprec, imprec
|
| 1514 |
+
|
| 1515 |
+
if options.get("verbose"):
|
| 1516 |
+
print("### input", x)
|
| 1517 |
+
print("### output", to_str(r[0] or fzero, 50) if isinstance(r, tuple) else r)
|
| 1518 |
+
print("### raw", r) # r[0], r[2]
|
| 1519 |
+
print()
|
| 1520 |
+
chop = options.get('chop', False)
|
| 1521 |
+
if chop:
|
| 1522 |
+
if chop is True:
|
| 1523 |
+
chop_prec = prec
|
| 1524 |
+
else:
|
| 1525 |
+
# convert (approximately) from given tolerance;
|
| 1526 |
+
# the formula here will will make 1e-i rounds to 0 for
|
| 1527 |
+
# i in the range +/-27 while 2e-i will not be chopped
|
| 1528 |
+
chop_prec = int(round(-3.321*math.log10(chop) + 2.5))
|
| 1529 |
+
if chop_prec == 3:
|
| 1530 |
+
chop_prec -= 1
|
| 1531 |
+
r = chop_parts(r, chop_prec)
|
| 1532 |
+
if options.get("strict"):
|
| 1533 |
+
check_target(x, r, prec)
|
| 1534 |
+
return r
|
| 1535 |
+
|
| 1536 |
+
|
| 1537 |
+
def quad_to_mpmath(q, ctx=None):
|
| 1538 |
+
"""Turn the quad returned by ``evalf`` into an ``mpf`` or ``mpc``. """
|
| 1539 |
+
mpc = make_mpc if ctx is None else ctx.make_mpc
|
| 1540 |
+
mpf = make_mpf if ctx is None else ctx.make_mpf
|
| 1541 |
+
if q is S.ComplexInfinity:
|
| 1542 |
+
raise NotImplementedError
|
| 1543 |
+
re, im, _, _ = q
|
| 1544 |
+
if im:
|
| 1545 |
+
if not re:
|
| 1546 |
+
re = fzero
|
| 1547 |
+
return mpc((re, im))
|
| 1548 |
+
elif re:
|
| 1549 |
+
return mpf(re)
|
| 1550 |
+
else:
|
| 1551 |
+
return mpf(fzero)
|
| 1552 |
+
|
| 1553 |
+
|
| 1554 |
+
class EvalfMixin:
|
| 1555 |
+
"""Mixin class adding evalf capability."""
|
| 1556 |
+
|
| 1557 |
+
__slots__ = () # type: tTuple[str, ...]
|
| 1558 |
+
|
| 1559 |
+
def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False):
|
| 1560 |
+
"""
|
| 1561 |
+
Evaluate the given formula to an accuracy of *n* digits.
|
| 1562 |
+
|
| 1563 |
+
Parameters
|
| 1564 |
+
==========
|
| 1565 |
+
|
| 1566 |
+
subs : dict, optional
|
| 1567 |
+
Substitute numerical values for symbols, e.g.
|
| 1568 |
+
``subs={x:3, y:1+pi}``. The substitutions must be given as a
|
| 1569 |
+
dictionary.
|
| 1570 |
+
|
| 1571 |
+
maxn : int, optional
|
| 1572 |
+
Allow a maximum temporary working precision of maxn digits.
|
| 1573 |
+
|
| 1574 |
+
chop : bool or number, optional
|
| 1575 |
+
Specifies how to replace tiny real or imaginary parts in
|
| 1576 |
+
subresults by exact zeros.
|
| 1577 |
+
|
| 1578 |
+
When ``True`` the chop value defaults to standard precision.
|
| 1579 |
+
|
| 1580 |
+
Otherwise the chop value is used to determine the
|
| 1581 |
+
magnitude of "small" for purposes of chopping.
|
| 1582 |
+
|
| 1583 |
+
>>> from sympy import N
|
| 1584 |
+
>>> x = 1e-4
|
| 1585 |
+
>>> N(x, chop=True)
|
| 1586 |
+
0.000100000000000000
|
| 1587 |
+
>>> N(x, chop=1e-5)
|
| 1588 |
+
0.000100000000000000
|
| 1589 |
+
>>> N(x, chop=1e-4)
|
| 1590 |
+
0
|
| 1591 |
+
|
| 1592 |
+
strict : bool, optional
|
| 1593 |
+
Raise ``PrecisionExhausted`` if any subresult fails to
|
| 1594 |
+
evaluate to full accuracy, given the available maxprec.
|
| 1595 |
+
|
| 1596 |
+
quad : str, optional
|
| 1597 |
+
Choose algorithm for numerical quadrature. By default,
|
| 1598 |
+
tanh-sinh quadrature is used. For oscillatory
|
| 1599 |
+
integrals on an infinite interval, try ``quad='osc'``.
|
| 1600 |
+
|
| 1601 |
+
verbose : bool, optional
|
| 1602 |
+
Print debug information.
|
| 1603 |
+
|
| 1604 |
+
Notes
|
| 1605 |
+
=====
|
| 1606 |
+
|
| 1607 |
+
When Floats are naively substituted into an expression,
|
| 1608 |
+
precision errors may adversely affect the result. For example,
|
| 1609 |
+
adding 1e16 (a Float) to 1 will truncate to 1e16; if 1e16 is
|
| 1610 |
+
then subtracted, the result will be 0.
|
| 1611 |
+
That is exactly what happens in the following:
|
| 1612 |
+
|
| 1613 |
+
>>> from sympy.abc import x, y, z
|
| 1614 |
+
>>> values = {x: 1e16, y: 1, z: 1e16}
|
| 1615 |
+
>>> (x + y - z).subs(values)
|
| 1616 |
+
0
|
| 1617 |
+
|
| 1618 |
+
Using the subs argument for evalf is the accurate way to
|
| 1619 |
+
evaluate such an expression:
|
| 1620 |
+
|
| 1621 |
+
>>> (x + y - z).evalf(subs=values)
|
| 1622 |
+
1.00000000000000
|
| 1623 |
+
"""
|
| 1624 |
+
from .numbers import Float, Number
|
| 1625 |
+
n = n if n is not None else 15
|
| 1626 |
+
|
| 1627 |
+
if subs and is_sequence(subs):
|
| 1628 |
+
raise TypeError('subs must be given as a dictionary')
|
| 1629 |
+
|
| 1630 |
+
# for sake of sage that doesn't like evalf(1)
|
| 1631 |
+
if n == 1 and isinstance(self, Number):
|
| 1632 |
+
from .expr import _mag
|
| 1633 |
+
rv = self.evalf(2, subs, maxn, chop, strict, quad, verbose)
|
| 1634 |
+
m = _mag(rv)
|
| 1635 |
+
rv = rv.round(1 - m)
|
| 1636 |
+
return rv
|
| 1637 |
+
|
| 1638 |
+
if not evalf_table:
|
| 1639 |
+
_create_evalf_table()
|
| 1640 |
+
prec = dps_to_prec(n)
|
| 1641 |
+
options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop,
|
| 1642 |
+
'strict': strict, 'verbose': verbose}
|
| 1643 |
+
if subs is not None:
|
| 1644 |
+
options['subs'] = subs
|
| 1645 |
+
if quad is not None:
|
| 1646 |
+
options['quad'] = quad
|
| 1647 |
+
try:
|
| 1648 |
+
result = evalf(self, prec + 4, options)
|
| 1649 |
+
except NotImplementedError:
|
| 1650 |
+
# Fall back to the ordinary evalf
|
| 1651 |
+
if hasattr(self, 'subs') and subs is not None: # issue 20291
|
| 1652 |
+
v = self.subs(subs)._eval_evalf(prec)
|
| 1653 |
+
else:
|
| 1654 |
+
v = self._eval_evalf(prec)
|
| 1655 |
+
if v is None:
|
| 1656 |
+
return self
|
| 1657 |
+
elif not v.is_number:
|
| 1658 |
+
return v
|
| 1659 |
+
try:
|
| 1660 |
+
# If the result is numerical, normalize it
|
| 1661 |
+
result = evalf(v, prec, options)
|
| 1662 |
+
except NotImplementedError:
|
| 1663 |
+
# Probably contains symbols or unknown functions
|
| 1664 |
+
return v
|
| 1665 |
+
if result is S.ComplexInfinity:
|
| 1666 |
+
return result
|
| 1667 |
+
re, im, re_acc, im_acc = result
|
| 1668 |
+
if re is S.NaN or im is S.NaN:
|
| 1669 |
+
return S.NaN
|
| 1670 |
+
if re:
|
| 1671 |
+
p = max(min(prec, re_acc), 1)
|
| 1672 |
+
re = Float._new(re, p)
|
| 1673 |
+
else:
|
| 1674 |
+
re = S.Zero
|
| 1675 |
+
if im:
|
| 1676 |
+
p = max(min(prec, im_acc), 1)
|
| 1677 |
+
im = Float._new(im, p)
|
| 1678 |
+
return re + im*S.ImaginaryUnit
|
| 1679 |
+
else:
|
| 1680 |
+
return re
|
| 1681 |
+
|
| 1682 |
+
n = evalf
|
| 1683 |
+
|
| 1684 |
+
def _evalf(self, prec):
|
| 1685 |
+
"""Helper for evalf. Does the same thing but takes binary precision"""
|
| 1686 |
+
r = self._eval_evalf(prec)
|
| 1687 |
+
if r is None:
|
| 1688 |
+
r = self
|
| 1689 |
+
return r
|
| 1690 |
+
|
| 1691 |
+
def _eval_evalf(self, prec):
|
| 1692 |
+
return
|
| 1693 |
+
|
| 1694 |
+
def _to_mpmath(self, prec, allow_ints=True):
|
| 1695 |
+
# mpmath functions accept ints as input
|
| 1696 |
+
errmsg = "cannot convert to mpmath number"
|
| 1697 |
+
if allow_ints and self.is_Integer:
|
| 1698 |
+
return self.p
|
| 1699 |
+
if hasattr(self, '_as_mpf_val'):
|
| 1700 |
+
return make_mpf(self._as_mpf_val(prec))
|
| 1701 |
+
try:
|
| 1702 |
+
result = evalf(self, prec, {})
|
| 1703 |
+
return quad_to_mpmath(result)
|
| 1704 |
+
except NotImplementedError:
|
| 1705 |
+
v = self._eval_evalf(prec)
|
| 1706 |
+
if v is None:
|
| 1707 |
+
raise ValueError(errmsg)
|
| 1708 |
+
if v.is_Float:
|
| 1709 |
+
return make_mpf(v._mpf_)
|
| 1710 |
+
# Number + Number*I is also fine
|
| 1711 |
+
re, im = v.as_real_imag()
|
| 1712 |
+
if allow_ints and re.is_Integer:
|
| 1713 |
+
re = from_int(re.p)
|
| 1714 |
+
elif re.is_Float:
|
| 1715 |
+
re = re._mpf_
|
| 1716 |
+
else:
|
| 1717 |
+
raise ValueError(errmsg)
|
| 1718 |
+
if allow_ints and im.is_Integer:
|
| 1719 |
+
im = from_int(im.p)
|
| 1720 |
+
elif im.is_Float:
|
| 1721 |
+
im = im._mpf_
|
| 1722 |
+
else:
|
| 1723 |
+
raise ValueError(errmsg)
|
| 1724 |
+
return make_mpc((re, im))
|
| 1725 |
+
|
| 1726 |
+
|
| 1727 |
+
def N(x, n=15, **options):
|
| 1728 |
+
r"""
|
| 1729 |
+
Calls x.evalf(n, \*\*options).
|
| 1730 |
+
|
| 1731 |
+
Explanations
|
| 1732 |
+
============
|
| 1733 |
+
|
| 1734 |
+
Both .n() and N() are equivalent to .evalf(); use the one that you like better.
|
| 1735 |
+
See also the docstring of .evalf() for information on the options.
|
| 1736 |
+
|
| 1737 |
+
Examples
|
| 1738 |
+
========
|
| 1739 |
+
|
| 1740 |
+
>>> from sympy import Sum, oo, N
|
| 1741 |
+
>>> from sympy.abc import k
|
| 1742 |
+
>>> Sum(1/k**k, (k, 1, oo))
|
| 1743 |
+
Sum(k**(-k), (k, 1, oo))
|
| 1744 |
+
>>> N(_, 4)
|
| 1745 |
+
1.291
|
| 1746 |
+
|
| 1747 |
+
"""
|
| 1748 |
+
# by using rational=True, any evaluation of a string
|
| 1749 |
+
# will be done using exact values for the Floats
|
| 1750 |
+
return sympify(x, rational=True).evalf(n, **options)
|
| 1751 |
+
|
| 1752 |
+
|
| 1753 |
+
def _evalf_with_bounded_error(x: 'Expr', eps: 'Optional[Expr]' = None,
|
| 1754 |
+
m: int = 0,
|
| 1755 |
+
options: Optional[OPT_DICT] = None) -> TMP_RES:
|
| 1756 |
+
"""
|
| 1757 |
+
Evaluate *x* to within a bounded absolute error.
|
| 1758 |
+
|
| 1759 |
+
Parameters
|
| 1760 |
+
==========
|
| 1761 |
+
|
| 1762 |
+
x : Expr
|
| 1763 |
+
The quantity to be evaluated.
|
| 1764 |
+
eps : Expr, None, optional (default=None)
|
| 1765 |
+
Positive real upper bound on the acceptable error.
|
| 1766 |
+
m : int, optional (default=0)
|
| 1767 |
+
If *eps* is None, then use 2**(-m) as the upper bound on the error.
|
| 1768 |
+
options: OPT_DICT
|
| 1769 |
+
As in the ``evalf`` function.
|
| 1770 |
+
|
| 1771 |
+
Returns
|
| 1772 |
+
=======
|
| 1773 |
+
|
| 1774 |
+
A tuple ``(re, im, re_acc, im_acc)``, as returned by ``evalf``.
|
| 1775 |
+
|
| 1776 |
+
See Also
|
| 1777 |
+
========
|
| 1778 |
+
|
| 1779 |
+
evalf
|
| 1780 |
+
|
| 1781 |
+
"""
|
| 1782 |
+
if eps is not None:
|
| 1783 |
+
if not (eps.is_Rational or eps.is_Float) or not eps > 0:
|
| 1784 |
+
raise ValueError("eps must be positive")
|
| 1785 |
+
r, _, _, _ = evalf(1/eps, 1, {})
|
| 1786 |
+
m = fastlog(r)
|
| 1787 |
+
|
| 1788 |
+
c, d, _, _ = evalf(x, 1, {})
|
| 1789 |
+
# Note: If x = a + b*I, then |a| <= 2|c| and |b| <= 2|d|, with equality
|
| 1790 |
+
# only in the zero case.
|
| 1791 |
+
# If a is non-zero, then |c| = 2**nc for some integer nc, and c has
|
| 1792 |
+
# bitcount 1. Therefore 2**fastlog(c) = 2**(nc+1) = 2|c| is an upper bound
|
| 1793 |
+
# on |a|. Likewise for b and d.
|
| 1794 |
+
nr, ni = fastlog(c), fastlog(d)
|
| 1795 |
+
n = max(nr, ni) + 1
|
| 1796 |
+
# If x is 0, then n is MINUS_INF, and p will be 1. Otherwise,
|
| 1797 |
+
# n - 1 bits get us past the integer parts of a and b, and +1 accounts for
|
| 1798 |
+
# the factor of <= sqrt(2) that is |x|/max(|a|, |b|).
|
| 1799 |
+
p = max(1, m + n + 1)
|
| 1800 |
+
|
| 1801 |
+
options = options or {}
|
| 1802 |
+
return evalf(x, p, options)
|