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/assumptions/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/ask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/ask_generated.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/assume.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/cnf.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/facts.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/lra_satask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/refine.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/satask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/__pycache__/sathandlers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__init__.py +13 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/calculus.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/common.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/matrices.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/ntheory.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/order.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/sets.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/handlers/common.py +156 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__init__.py +5 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/calculus.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/common.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/matrices.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/ntheory.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/order.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/sets.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/calculus.py +82 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/common.py +81 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/matrices.py +511 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/ntheory.py +126 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/order.py +390 -0
- lib/python3.12/site-packages/sympy/assumptions/predicates/sets.py +399 -0
- lib/python3.12/site-packages/sympy/parsing/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/__pycache__/ast_parser.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/__pycache__/mathematica.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/__pycache__/maxima.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/c/__init__.py +1 -0
- lib/python3.12/site-packages/sympy/parsing/c/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/c/__pycache__/c_parser.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/c/c_parser.py +1058 -0
- lib/python3.12/site-packages/sympy/parsing/latex/LICENSE.txt +21 -0
- lib/python3.12/site-packages/sympy/parsing/latex/LaTeX.g4 +312 -0
- lib/python3.12/site-packages/sympy/parsing/latex/__init__.py +66 -0
- lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/_build_latex_antlr.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/_parse_latex_antlr.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/errors.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/parsing/latex/_antlr/__init__.py +9 -0
- lib/python3.12/site-packages/sympy/parsing/latex/_antlr/__pycache__/__init__.cpython-312.pyc +0 -0
lib/python3.12/site-packages/sympy/assumptions/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (727 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/ask.cpython-312.pyc
ADDED
|
Binary file (24.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/ask_generated.cpython-312.pyc
ADDED
|
Binary file (53.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/assume.cpython-312.pyc
ADDED
|
Binary file (18.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/cnf.cpython-312.pyc
ADDED
|
Binary file (23.7 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/facts.cpython-312.pyc
ADDED
|
Binary file (14.9 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/lra_satask.cpython-312.pyc
ADDED
|
Binary file (12.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/refine.cpython-312.pyc
ADDED
|
Binary file (16 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/satask.cpython-312.pyc
ADDED
|
Binary file (13.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/__pycache__/sathandlers.cpython-312.pyc
ADDED
|
Binary file (17.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Multipledispatch handlers for ``Predicate`` are implemented here.
|
| 3 |
+
Handlers in this module are not directly imported to other modules in
|
| 4 |
+
order to avoid circular import problem.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from .common import (AskHandler, CommonHandler,
|
| 8 |
+
test_closed_group)
|
| 9 |
+
|
| 10 |
+
__all__ = [
|
| 11 |
+
'AskHandler', 'CommonHandler',
|
| 12 |
+
'test_closed_group'
|
| 13 |
+
]
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (529 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/calculus.cpython-312.pyc
ADDED
|
Binary file (8.94 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/common.cpython-312.pyc
ADDED
|
Binary file (6.7 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/matrices.cpython-312.pyc
ADDED
|
Binary file (39.8 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/ntheory.cpython-312.pyc
ADDED
|
Binary file (11.3 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/order.cpython-312.pyc
ADDED
|
Binary file (21.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/__pycache__/sets.cpython-312.pyc
ADDED
|
Binary file (36.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/handlers/common.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module defines base class for handlers and some core handlers:
|
| 3 |
+
``Q.commutative`` and ``Q.is_true``.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from sympy.assumptions import Q, ask, AppliedPredicate
|
| 7 |
+
from sympy.core import Basic, Symbol
|
| 8 |
+
from sympy.core.logic import _fuzzy_group
|
| 9 |
+
from sympy.core.numbers import NaN, Number
|
| 10 |
+
from sympy.logic.boolalg import (And, BooleanTrue, BooleanFalse, conjuncts,
|
| 11 |
+
Equivalent, Implies, Not, Or)
|
| 12 |
+
from sympy.utilities.exceptions import sympy_deprecation_warning
|
| 13 |
+
|
| 14 |
+
from ..predicates.common import CommutativePredicate, IsTruePredicate
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class AskHandler:
|
| 18 |
+
"""Base class that all Ask Handlers must inherit."""
|
| 19 |
+
def __new__(cls, *args, **kwargs):
|
| 20 |
+
sympy_deprecation_warning(
|
| 21 |
+
"""
|
| 22 |
+
The AskHandler system is deprecated. The AskHandler class should
|
| 23 |
+
be replaced with the multipledispatch handler of Predicate
|
| 24 |
+
""",
|
| 25 |
+
deprecated_since_version="1.8",
|
| 26 |
+
active_deprecations_target='deprecated-askhandler',
|
| 27 |
+
)
|
| 28 |
+
return super().__new__(cls, *args, **kwargs)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class CommonHandler(AskHandler):
|
| 32 |
+
# Deprecated
|
| 33 |
+
"""Defines some useful methods common to most Handlers. """
|
| 34 |
+
|
| 35 |
+
@staticmethod
|
| 36 |
+
def AlwaysTrue(expr, assumptions):
|
| 37 |
+
return True
|
| 38 |
+
|
| 39 |
+
@staticmethod
|
| 40 |
+
def AlwaysFalse(expr, assumptions):
|
| 41 |
+
return False
|
| 42 |
+
|
| 43 |
+
@staticmethod
|
| 44 |
+
def AlwaysNone(expr, assumptions):
|
| 45 |
+
return None
|
| 46 |
+
|
| 47 |
+
NaN = AlwaysFalse
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# CommutativePredicate
|
| 51 |
+
|
| 52 |
+
@CommutativePredicate.register(Symbol)
|
| 53 |
+
def _(expr, assumptions):
|
| 54 |
+
"""Objects are expected to be commutative unless otherwise stated"""
|
| 55 |
+
assumps = conjuncts(assumptions)
|
| 56 |
+
if expr.is_commutative is not None:
|
| 57 |
+
return expr.is_commutative and not ~Q.commutative(expr) in assumps
|
| 58 |
+
if Q.commutative(expr) in assumps:
|
| 59 |
+
return True
|
| 60 |
+
elif ~Q.commutative(expr) in assumps:
|
| 61 |
+
return False
|
| 62 |
+
return True
|
| 63 |
+
|
| 64 |
+
@CommutativePredicate.register(Basic)
|
| 65 |
+
def _(expr, assumptions):
|
| 66 |
+
for arg in expr.args:
|
| 67 |
+
if not ask(Q.commutative(arg), assumptions):
|
| 68 |
+
return False
|
| 69 |
+
return True
|
| 70 |
+
|
| 71 |
+
@CommutativePredicate.register(Number)
|
| 72 |
+
def _(expr, assumptions):
|
| 73 |
+
return True
|
| 74 |
+
|
| 75 |
+
@CommutativePredicate.register(NaN)
|
| 76 |
+
def _(expr, assumptions):
|
| 77 |
+
return True
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
# IsTruePredicate
|
| 81 |
+
|
| 82 |
+
@IsTruePredicate.register(bool)
|
| 83 |
+
def _(expr, assumptions):
|
| 84 |
+
return expr
|
| 85 |
+
|
| 86 |
+
@IsTruePredicate.register(BooleanTrue)
|
| 87 |
+
def _(expr, assumptions):
|
| 88 |
+
return True
|
| 89 |
+
|
| 90 |
+
@IsTruePredicate.register(BooleanFalse)
|
| 91 |
+
def _(expr, assumptions):
|
| 92 |
+
return False
|
| 93 |
+
|
| 94 |
+
@IsTruePredicate.register(AppliedPredicate)
|
| 95 |
+
def _(expr, assumptions):
|
| 96 |
+
return ask(expr, assumptions)
|
| 97 |
+
|
| 98 |
+
@IsTruePredicate.register(Not)
|
| 99 |
+
def _(expr, assumptions):
|
| 100 |
+
arg = expr.args[0]
|
| 101 |
+
if arg.is_Symbol:
|
| 102 |
+
# symbol used as abstract boolean object
|
| 103 |
+
return None
|
| 104 |
+
value = ask(arg, assumptions=assumptions)
|
| 105 |
+
if value in (True, False):
|
| 106 |
+
return not value
|
| 107 |
+
else:
|
| 108 |
+
return None
|
| 109 |
+
|
| 110 |
+
@IsTruePredicate.register(Or)
|
| 111 |
+
def _(expr, assumptions):
|
| 112 |
+
result = False
|
| 113 |
+
for arg in expr.args:
|
| 114 |
+
p = ask(arg, assumptions=assumptions)
|
| 115 |
+
if p is True:
|
| 116 |
+
return True
|
| 117 |
+
if p is None:
|
| 118 |
+
result = None
|
| 119 |
+
return result
|
| 120 |
+
|
| 121 |
+
@IsTruePredicate.register(And)
|
| 122 |
+
def _(expr, assumptions):
|
| 123 |
+
result = True
|
| 124 |
+
for arg in expr.args:
|
| 125 |
+
p = ask(arg, assumptions=assumptions)
|
| 126 |
+
if p is False:
|
| 127 |
+
return False
|
| 128 |
+
if p is None:
|
| 129 |
+
result = None
|
| 130 |
+
return result
|
| 131 |
+
|
| 132 |
+
@IsTruePredicate.register(Implies)
|
| 133 |
+
def _(expr, assumptions):
|
| 134 |
+
p, q = expr.args
|
| 135 |
+
return ask(~p | q, assumptions=assumptions)
|
| 136 |
+
|
| 137 |
+
@IsTruePredicate.register(Equivalent)
|
| 138 |
+
def _(expr, assumptions):
|
| 139 |
+
p, q = expr.args
|
| 140 |
+
pt = ask(p, assumptions=assumptions)
|
| 141 |
+
if pt is None:
|
| 142 |
+
return None
|
| 143 |
+
qt = ask(q, assumptions=assumptions)
|
| 144 |
+
if qt is None:
|
| 145 |
+
return None
|
| 146 |
+
return pt == qt
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
#### Helper methods
|
| 150 |
+
def test_closed_group(expr, assumptions, key):
|
| 151 |
+
"""
|
| 152 |
+
Test for membership in a group with respect
|
| 153 |
+
to the current operation.
|
| 154 |
+
"""
|
| 155 |
+
return _fuzzy_group(
|
| 156 |
+
(ask(key(a), assumptions) for a in expr.args), quick_exit=True)
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Module to implement predicate classes.
|
| 3 |
+
|
| 4 |
+
Class of every predicate registered to ``Q`` is defined here.
|
| 5 |
+
"""
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (327 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/calculus.cpython-312.pyc
ADDED
|
Binary file (2.54 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/common.cpython-312.pyc
ADDED
|
Binary file (3.16 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/matrices.cpython-312.pyc
ADDED
|
Binary file (14.4 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/ntheory.cpython-312.pyc
ADDED
|
Binary file (3.24 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/order.cpython-312.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/__pycache__/sets.cpython-312.pyc
ADDED
|
Binary file (10.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/assumptions/predicates/calculus.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate
|
| 2 |
+
from sympy.multipledispatch import Dispatcher
|
| 3 |
+
|
| 4 |
+
class FinitePredicate(Predicate):
|
| 5 |
+
"""
|
| 6 |
+
Finite number predicate.
|
| 7 |
+
|
| 8 |
+
Explanation
|
| 9 |
+
===========
|
| 10 |
+
|
| 11 |
+
``Q.finite(x)`` is true if ``x`` is a number but neither an infinity
|
| 12 |
+
nor a ``NaN``. In other words, ``ask(Q.finite(x))`` is true for all
|
| 13 |
+
numerical ``x`` having a bounded absolute value.
|
| 14 |
+
|
| 15 |
+
Examples
|
| 16 |
+
========
|
| 17 |
+
|
| 18 |
+
>>> from sympy import Q, ask, S, oo, I, zoo
|
| 19 |
+
>>> from sympy.abc import x
|
| 20 |
+
>>> ask(Q.finite(oo))
|
| 21 |
+
False
|
| 22 |
+
>>> ask(Q.finite(-oo))
|
| 23 |
+
False
|
| 24 |
+
>>> ask(Q.finite(zoo))
|
| 25 |
+
False
|
| 26 |
+
>>> ask(Q.finite(1))
|
| 27 |
+
True
|
| 28 |
+
>>> ask(Q.finite(2 + 3*I))
|
| 29 |
+
True
|
| 30 |
+
>>> ask(Q.finite(x), Q.positive(x))
|
| 31 |
+
True
|
| 32 |
+
>>> print(ask(Q.finite(S.NaN)))
|
| 33 |
+
None
|
| 34 |
+
|
| 35 |
+
References
|
| 36 |
+
==========
|
| 37 |
+
|
| 38 |
+
.. [1] https://en.wikipedia.org/wiki/Finite
|
| 39 |
+
|
| 40 |
+
"""
|
| 41 |
+
name = 'finite'
|
| 42 |
+
handler = Dispatcher(
|
| 43 |
+
"FiniteHandler",
|
| 44 |
+
doc=("Handler for Q.finite. Test that an expression is bounded respect"
|
| 45 |
+
" to all its variables.")
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class InfinitePredicate(Predicate):
|
| 50 |
+
"""
|
| 51 |
+
Infinite number predicate.
|
| 52 |
+
|
| 53 |
+
``Q.infinite(x)`` is true iff the absolute value of ``x`` is
|
| 54 |
+
infinity.
|
| 55 |
+
|
| 56 |
+
"""
|
| 57 |
+
# TODO: Add examples
|
| 58 |
+
name = 'infinite'
|
| 59 |
+
handler = Dispatcher(
|
| 60 |
+
"InfiniteHandler",
|
| 61 |
+
doc="""Handler for Q.infinite key."""
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class PositiveInfinitePredicate(Predicate):
|
| 66 |
+
"""
|
| 67 |
+
Positive infinity predicate.
|
| 68 |
+
|
| 69 |
+
``Q.positive_infinite(x)`` is true iff ``x`` is positive infinity ``oo``.
|
| 70 |
+
"""
|
| 71 |
+
name = 'positive_infinite'
|
| 72 |
+
handler = Dispatcher("PositiveInfiniteHandler")
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class NegativeInfinitePredicate(Predicate):
|
| 76 |
+
"""
|
| 77 |
+
Negative infinity predicate.
|
| 78 |
+
|
| 79 |
+
``Q.negative_infinite(x)`` is true iff ``x`` is negative infinity ``-oo``.
|
| 80 |
+
"""
|
| 81 |
+
name = 'negative_infinite'
|
| 82 |
+
handler = Dispatcher("NegativeInfiniteHandler")
|
lib/python3.12/site-packages/sympy/assumptions/predicates/common.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate, AppliedPredicate, Q
|
| 2 |
+
from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le
|
| 3 |
+
from sympy.multipledispatch import Dispatcher
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class CommutativePredicate(Predicate):
|
| 7 |
+
"""
|
| 8 |
+
Commutative predicate.
|
| 9 |
+
|
| 10 |
+
Explanation
|
| 11 |
+
===========
|
| 12 |
+
|
| 13 |
+
``ask(Q.commutative(x))`` is true iff ``x`` commutes with any other
|
| 14 |
+
object with respect to multiplication operation.
|
| 15 |
+
|
| 16 |
+
"""
|
| 17 |
+
# TODO: Add examples
|
| 18 |
+
name = 'commutative'
|
| 19 |
+
handler = Dispatcher("CommutativeHandler", doc="Handler for key 'commutative'.")
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le}
|
| 23 |
+
|
| 24 |
+
class IsTruePredicate(Predicate):
|
| 25 |
+
"""
|
| 26 |
+
Generic predicate.
|
| 27 |
+
|
| 28 |
+
Explanation
|
| 29 |
+
===========
|
| 30 |
+
|
| 31 |
+
``ask(Q.is_true(x))`` is true iff ``x`` is true. This only makes
|
| 32 |
+
sense if ``x`` is a boolean object.
|
| 33 |
+
|
| 34 |
+
Examples
|
| 35 |
+
========
|
| 36 |
+
|
| 37 |
+
>>> from sympy import ask, Q
|
| 38 |
+
>>> from sympy.abc import x, y
|
| 39 |
+
>>> ask(Q.is_true(True))
|
| 40 |
+
True
|
| 41 |
+
|
| 42 |
+
Wrapping another applied predicate just returns the applied predicate.
|
| 43 |
+
|
| 44 |
+
>>> Q.is_true(Q.even(x))
|
| 45 |
+
Q.even(x)
|
| 46 |
+
|
| 47 |
+
Wrapping binary relation classes in SymPy core returns applied binary
|
| 48 |
+
relational predicates.
|
| 49 |
+
|
| 50 |
+
>>> from sympy import Eq, Gt
|
| 51 |
+
>>> Q.is_true(Eq(x, y))
|
| 52 |
+
Q.eq(x, y)
|
| 53 |
+
>>> Q.is_true(Gt(x, y))
|
| 54 |
+
Q.gt(x, y)
|
| 55 |
+
|
| 56 |
+
Notes
|
| 57 |
+
=====
|
| 58 |
+
|
| 59 |
+
This class is designed to wrap the boolean objects so that they can
|
| 60 |
+
behave as if they are applied predicates. Consequently, wrapping another
|
| 61 |
+
applied predicate is unnecessary and thus it just returns the argument.
|
| 62 |
+
Also, binary relation classes in SymPy core have binary predicates to
|
| 63 |
+
represent themselves and thus wrapping them with ``Q.is_true`` converts them
|
| 64 |
+
to these applied predicates.
|
| 65 |
+
|
| 66 |
+
"""
|
| 67 |
+
name = 'is_true'
|
| 68 |
+
handler = Dispatcher(
|
| 69 |
+
"IsTrueHandler",
|
| 70 |
+
doc="Wrapper allowing to query the truth value of a boolean expression."
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
def __call__(self, arg):
|
| 74 |
+
# No need to wrap another predicate
|
| 75 |
+
if isinstance(arg, AppliedPredicate):
|
| 76 |
+
return arg
|
| 77 |
+
# Convert relational predicates instead of wrapping them
|
| 78 |
+
if getattr(arg, "is_Relational", False):
|
| 79 |
+
pred = binrelpreds[type(arg)]
|
| 80 |
+
return pred(*arg.args)
|
| 81 |
+
return super().__call__(arg)
|
lib/python3.12/site-packages/sympy/assumptions/predicates/matrices.py
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate
|
| 2 |
+
from sympy.multipledispatch import Dispatcher
|
| 3 |
+
|
| 4 |
+
class SquarePredicate(Predicate):
|
| 5 |
+
"""
|
| 6 |
+
Square matrix predicate.
|
| 7 |
+
|
| 8 |
+
Explanation
|
| 9 |
+
===========
|
| 10 |
+
|
| 11 |
+
``Q.square(x)`` is true iff ``x`` is a square matrix. A square matrix
|
| 12 |
+
is a matrix with the same number of rows and columns.
|
| 13 |
+
|
| 14 |
+
Examples
|
| 15 |
+
========
|
| 16 |
+
|
| 17 |
+
>>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity
|
| 18 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 19 |
+
>>> Y = MatrixSymbol('X', 2, 3)
|
| 20 |
+
>>> ask(Q.square(X))
|
| 21 |
+
True
|
| 22 |
+
>>> ask(Q.square(Y))
|
| 23 |
+
False
|
| 24 |
+
>>> ask(Q.square(ZeroMatrix(3, 3)))
|
| 25 |
+
True
|
| 26 |
+
>>> ask(Q.square(Identity(3)))
|
| 27 |
+
True
|
| 28 |
+
|
| 29 |
+
References
|
| 30 |
+
==========
|
| 31 |
+
|
| 32 |
+
.. [1] https://en.wikipedia.org/wiki/Square_matrix
|
| 33 |
+
|
| 34 |
+
"""
|
| 35 |
+
name = 'square'
|
| 36 |
+
handler = Dispatcher("SquareHandler", doc="Handler for Q.square.")
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class SymmetricPredicate(Predicate):
|
| 40 |
+
"""
|
| 41 |
+
Symmetric matrix predicate.
|
| 42 |
+
|
| 43 |
+
Explanation
|
| 44 |
+
===========
|
| 45 |
+
|
| 46 |
+
``Q.symmetric(x)`` is true iff ``x`` is a square matrix and is equal to
|
| 47 |
+
its transpose. Every square diagonal matrix is a symmetric matrix.
|
| 48 |
+
|
| 49 |
+
Examples
|
| 50 |
+
========
|
| 51 |
+
|
| 52 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 53 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 54 |
+
>>> Y = MatrixSymbol('Y', 2, 3)
|
| 55 |
+
>>> Z = MatrixSymbol('Z', 2, 2)
|
| 56 |
+
>>> ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z))
|
| 57 |
+
True
|
| 58 |
+
>>> ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z))
|
| 59 |
+
True
|
| 60 |
+
>>> ask(Q.symmetric(Y))
|
| 61 |
+
False
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
References
|
| 65 |
+
==========
|
| 66 |
+
|
| 67 |
+
.. [1] https://en.wikipedia.org/wiki/Symmetric_matrix
|
| 68 |
+
|
| 69 |
+
"""
|
| 70 |
+
# TODO: Add handlers to make these keys work with
|
| 71 |
+
# actual matrices and add more examples in the docstring.
|
| 72 |
+
name = 'symmetric'
|
| 73 |
+
handler = Dispatcher("SymmetricHandler", doc="Handler for Q.symmetric.")
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class InvertiblePredicate(Predicate):
|
| 77 |
+
"""
|
| 78 |
+
Invertible matrix predicate.
|
| 79 |
+
|
| 80 |
+
Explanation
|
| 81 |
+
===========
|
| 82 |
+
|
| 83 |
+
``Q.invertible(x)`` is true iff ``x`` is an invertible matrix.
|
| 84 |
+
A square matrix is called invertible only if its determinant is 0.
|
| 85 |
+
|
| 86 |
+
Examples
|
| 87 |
+
========
|
| 88 |
+
|
| 89 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 90 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 91 |
+
>>> Y = MatrixSymbol('Y', 2, 3)
|
| 92 |
+
>>> Z = MatrixSymbol('Z', 2, 2)
|
| 93 |
+
>>> ask(Q.invertible(X*Y), Q.invertible(X))
|
| 94 |
+
False
|
| 95 |
+
>>> ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z))
|
| 96 |
+
True
|
| 97 |
+
>>> ask(Q.invertible(X), Q.fullrank(X) & Q.square(X))
|
| 98 |
+
True
|
| 99 |
+
|
| 100 |
+
References
|
| 101 |
+
==========
|
| 102 |
+
|
| 103 |
+
.. [1] https://en.wikipedia.org/wiki/Invertible_matrix
|
| 104 |
+
|
| 105 |
+
"""
|
| 106 |
+
name = 'invertible'
|
| 107 |
+
handler = Dispatcher("InvertibleHandler", doc="Handler for Q.invertible.")
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class OrthogonalPredicate(Predicate):
|
| 111 |
+
"""
|
| 112 |
+
Orthogonal matrix predicate.
|
| 113 |
+
|
| 114 |
+
Explanation
|
| 115 |
+
===========
|
| 116 |
+
|
| 117 |
+
``Q.orthogonal(x)`` is true iff ``x`` is an orthogonal matrix.
|
| 118 |
+
A square matrix ``M`` is an orthogonal matrix if it satisfies
|
| 119 |
+
``M^TM = MM^T = I`` where ``M^T`` is the transpose matrix of
|
| 120 |
+
``M`` and ``I`` is an identity matrix. Note that an orthogonal
|
| 121 |
+
matrix is necessarily invertible.
|
| 122 |
+
|
| 123 |
+
Examples
|
| 124 |
+
========
|
| 125 |
+
|
| 126 |
+
>>> from sympy import Q, ask, MatrixSymbol, Identity
|
| 127 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 128 |
+
>>> Y = MatrixSymbol('Y', 2, 3)
|
| 129 |
+
>>> Z = MatrixSymbol('Z', 2, 2)
|
| 130 |
+
>>> ask(Q.orthogonal(Y))
|
| 131 |
+
False
|
| 132 |
+
>>> ask(Q.orthogonal(X*Z*X), Q.orthogonal(X) & Q.orthogonal(Z))
|
| 133 |
+
True
|
| 134 |
+
>>> ask(Q.orthogonal(Identity(3)))
|
| 135 |
+
True
|
| 136 |
+
>>> ask(Q.invertible(X), Q.orthogonal(X))
|
| 137 |
+
True
|
| 138 |
+
|
| 139 |
+
References
|
| 140 |
+
==========
|
| 141 |
+
|
| 142 |
+
.. [1] https://en.wikipedia.org/wiki/Orthogonal_matrix
|
| 143 |
+
|
| 144 |
+
"""
|
| 145 |
+
name = 'orthogonal'
|
| 146 |
+
handler = Dispatcher("OrthogonalHandler", doc="Handler for key 'orthogonal'.")
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class UnitaryPredicate(Predicate):
|
| 150 |
+
"""
|
| 151 |
+
Unitary matrix predicate.
|
| 152 |
+
|
| 153 |
+
Explanation
|
| 154 |
+
===========
|
| 155 |
+
|
| 156 |
+
``Q.unitary(x)`` is true iff ``x`` is a unitary matrix.
|
| 157 |
+
Unitary matrix is an analogue to orthogonal matrix. A square
|
| 158 |
+
matrix ``M`` with complex elements is unitary if :math:``M^TM = MM^T= I``
|
| 159 |
+
where :math:``M^T`` is the conjugate transpose matrix of ``M``.
|
| 160 |
+
|
| 161 |
+
Examples
|
| 162 |
+
========
|
| 163 |
+
|
| 164 |
+
>>> from sympy import Q, ask, MatrixSymbol, Identity
|
| 165 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 166 |
+
>>> Y = MatrixSymbol('Y', 2, 3)
|
| 167 |
+
>>> Z = MatrixSymbol('Z', 2, 2)
|
| 168 |
+
>>> ask(Q.unitary(Y))
|
| 169 |
+
False
|
| 170 |
+
>>> ask(Q.unitary(X*Z*X), Q.unitary(X) & Q.unitary(Z))
|
| 171 |
+
True
|
| 172 |
+
>>> ask(Q.unitary(Identity(3)))
|
| 173 |
+
True
|
| 174 |
+
|
| 175 |
+
References
|
| 176 |
+
==========
|
| 177 |
+
|
| 178 |
+
.. [1] https://en.wikipedia.org/wiki/Unitary_matrix
|
| 179 |
+
|
| 180 |
+
"""
|
| 181 |
+
name = 'unitary'
|
| 182 |
+
handler = Dispatcher("UnitaryHandler", doc="Handler for key 'unitary'.")
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
class FullRankPredicate(Predicate):
|
| 186 |
+
"""
|
| 187 |
+
Fullrank matrix predicate.
|
| 188 |
+
|
| 189 |
+
Explanation
|
| 190 |
+
===========
|
| 191 |
+
|
| 192 |
+
``Q.fullrank(x)`` is true iff ``x`` is a full rank matrix.
|
| 193 |
+
A matrix is full rank if all rows and columns of the matrix
|
| 194 |
+
are linearly independent. A square matrix is full rank iff
|
| 195 |
+
its determinant is nonzero.
|
| 196 |
+
|
| 197 |
+
Examples
|
| 198 |
+
========
|
| 199 |
+
|
| 200 |
+
>>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity
|
| 201 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 202 |
+
>>> ask(Q.fullrank(X.T), Q.fullrank(X))
|
| 203 |
+
True
|
| 204 |
+
>>> ask(Q.fullrank(ZeroMatrix(3, 3)))
|
| 205 |
+
False
|
| 206 |
+
>>> ask(Q.fullrank(Identity(3)))
|
| 207 |
+
True
|
| 208 |
+
|
| 209 |
+
"""
|
| 210 |
+
name = 'fullrank'
|
| 211 |
+
handler = Dispatcher("FullRankHandler", doc="Handler for key 'fullrank'.")
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
class PositiveDefinitePredicate(Predicate):
|
| 215 |
+
r"""
|
| 216 |
+
Positive definite matrix predicate.
|
| 217 |
+
|
| 218 |
+
Explanation
|
| 219 |
+
===========
|
| 220 |
+
|
| 221 |
+
If $M$ is a :math:`n \times n` symmetric real matrix, it is said
|
| 222 |
+
to be positive definite if :math:`Z^TMZ` is positive for
|
| 223 |
+
every non-zero column vector $Z$ of $n$ real numbers.
|
| 224 |
+
|
| 225 |
+
Examples
|
| 226 |
+
========
|
| 227 |
+
|
| 228 |
+
>>> from sympy import Q, ask, MatrixSymbol, Identity
|
| 229 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 230 |
+
>>> Y = MatrixSymbol('Y', 2, 3)
|
| 231 |
+
>>> Z = MatrixSymbol('Z', 2, 2)
|
| 232 |
+
>>> ask(Q.positive_definite(Y))
|
| 233 |
+
False
|
| 234 |
+
>>> ask(Q.positive_definite(Identity(3)))
|
| 235 |
+
True
|
| 236 |
+
>>> ask(Q.positive_definite(X + Z), Q.positive_definite(X) &
|
| 237 |
+
... Q.positive_definite(Z))
|
| 238 |
+
True
|
| 239 |
+
|
| 240 |
+
References
|
| 241 |
+
==========
|
| 242 |
+
|
| 243 |
+
.. [1] https://en.wikipedia.org/wiki/Positive-definite_matrix
|
| 244 |
+
|
| 245 |
+
"""
|
| 246 |
+
name = "positive_definite"
|
| 247 |
+
handler = Dispatcher("PositiveDefiniteHandler", doc="Handler for key 'positive_definite'.")
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
class UpperTriangularPredicate(Predicate):
|
| 251 |
+
"""
|
| 252 |
+
Upper triangular matrix predicate.
|
| 253 |
+
|
| 254 |
+
Explanation
|
| 255 |
+
===========
|
| 256 |
+
|
| 257 |
+
A matrix $M$ is called upper triangular matrix if :math:`M_{ij}=0`
|
| 258 |
+
for :math:`i<j`.
|
| 259 |
+
|
| 260 |
+
Examples
|
| 261 |
+
========
|
| 262 |
+
|
| 263 |
+
>>> from sympy import Q, ask, ZeroMatrix, Identity
|
| 264 |
+
>>> ask(Q.upper_triangular(Identity(3)))
|
| 265 |
+
True
|
| 266 |
+
>>> ask(Q.upper_triangular(ZeroMatrix(3, 3)))
|
| 267 |
+
True
|
| 268 |
+
|
| 269 |
+
References
|
| 270 |
+
==========
|
| 271 |
+
|
| 272 |
+
.. [1] https://mathworld.wolfram.com/UpperTriangularMatrix.html
|
| 273 |
+
|
| 274 |
+
"""
|
| 275 |
+
name = "upper_triangular"
|
| 276 |
+
handler = Dispatcher("UpperTriangularHandler", doc="Handler for key 'upper_triangular'.")
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
class LowerTriangularPredicate(Predicate):
|
| 280 |
+
"""
|
| 281 |
+
Lower triangular matrix predicate.
|
| 282 |
+
|
| 283 |
+
Explanation
|
| 284 |
+
===========
|
| 285 |
+
|
| 286 |
+
A matrix $M$ is called lower triangular matrix if :math:`M_{ij}=0`
|
| 287 |
+
for :math:`i>j`.
|
| 288 |
+
|
| 289 |
+
Examples
|
| 290 |
+
========
|
| 291 |
+
|
| 292 |
+
>>> from sympy import Q, ask, ZeroMatrix, Identity
|
| 293 |
+
>>> ask(Q.lower_triangular(Identity(3)))
|
| 294 |
+
True
|
| 295 |
+
>>> ask(Q.lower_triangular(ZeroMatrix(3, 3)))
|
| 296 |
+
True
|
| 297 |
+
|
| 298 |
+
References
|
| 299 |
+
==========
|
| 300 |
+
|
| 301 |
+
.. [1] https://mathworld.wolfram.com/LowerTriangularMatrix.html
|
| 302 |
+
|
| 303 |
+
"""
|
| 304 |
+
name = "lower_triangular"
|
| 305 |
+
handler = Dispatcher("LowerTriangularHandler", doc="Handler for key 'lower_triangular'.")
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
class DiagonalPredicate(Predicate):
|
| 309 |
+
"""
|
| 310 |
+
Diagonal matrix predicate.
|
| 311 |
+
|
| 312 |
+
Explanation
|
| 313 |
+
===========
|
| 314 |
+
|
| 315 |
+
``Q.diagonal(x)`` is true iff ``x`` is a diagonal matrix. A diagonal
|
| 316 |
+
matrix is a matrix in which the entries outside the main diagonal
|
| 317 |
+
are all zero.
|
| 318 |
+
|
| 319 |
+
Examples
|
| 320 |
+
========
|
| 321 |
+
|
| 322 |
+
>>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix
|
| 323 |
+
>>> X = MatrixSymbol('X', 2, 2)
|
| 324 |
+
>>> ask(Q.diagonal(ZeroMatrix(3, 3)))
|
| 325 |
+
True
|
| 326 |
+
>>> ask(Q.diagonal(X), Q.lower_triangular(X) &
|
| 327 |
+
... Q.upper_triangular(X))
|
| 328 |
+
True
|
| 329 |
+
|
| 330 |
+
References
|
| 331 |
+
==========
|
| 332 |
+
|
| 333 |
+
.. [1] https://en.wikipedia.org/wiki/Diagonal_matrix
|
| 334 |
+
|
| 335 |
+
"""
|
| 336 |
+
name = "diagonal"
|
| 337 |
+
handler = Dispatcher("DiagonalHandler", doc="Handler for key 'diagonal'.")
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
class IntegerElementsPredicate(Predicate):
|
| 341 |
+
"""
|
| 342 |
+
Integer elements matrix predicate.
|
| 343 |
+
|
| 344 |
+
Explanation
|
| 345 |
+
===========
|
| 346 |
+
|
| 347 |
+
``Q.integer_elements(x)`` is true iff all the elements of ``x``
|
| 348 |
+
are integers.
|
| 349 |
+
|
| 350 |
+
Examples
|
| 351 |
+
========
|
| 352 |
+
|
| 353 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 354 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 355 |
+
>>> ask(Q.integer(X[1, 2]), Q.integer_elements(X))
|
| 356 |
+
True
|
| 357 |
+
|
| 358 |
+
"""
|
| 359 |
+
name = "integer_elements"
|
| 360 |
+
handler = Dispatcher("IntegerElementsHandler", doc="Handler for key 'integer_elements'.")
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
class RealElementsPredicate(Predicate):
|
| 364 |
+
"""
|
| 365 |
+
Real elements matrix predicate.
|
| 366 |
+
|
| 367 |
+
Explanation
|
| 368 |
+
===========
|
| 369 |
+
|
| 370 |
+
``Q.real_elements(x)`` is true iff all the elements of ``x``
|
| 371 |
+
are real numbers.
|
| 372 |
+
|
| 373 |
+
Examples
|
| 374 |
+
========
|
| 375 |
+
|
| 376 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 377 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 378 |
+
>>> ask(Q.real(X[1, 2]), Q.real_elements(X))
|
| 379 |
+
True
|
| 380 |
+
|
| 381 |
+
"""
|
| 382 |
+
name = "real_elements"
|
| 383 |
+
handler = Dispatcher("RealElementsHandler", doc="Handler for key 'real_elements'.")
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
class ComplexElementsPredicate(Predicate):
|
| 387 |
+
"""
|
| 388 |
+
Complex elements matrix predicate.
|
| 389 |
+
|
| 390 |
+
Explanation
|
| 391 |
+
===========
|
| 392 |
+
|
| 393 |
+
``Q.complex_elements(x)`` is true iff all the elements of ``x``
|
| 394 |
+
are complex numbers.
|
| 395 |
+
|
| 396 |
+
Examples
|
| 397 |
+
========
|
| 398 |
+
|
| 399 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 400 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 401 |
+
>>> ask(Q.complex(X[1, 2]), Q.complex_elements(X))
|
| 402 |
+
True
|
| 403 |
+
>>> ask(Q.complex_elements(X), Q.integer_elements(X))
|
| 404 |
+
True
|
| 405 |
+
|
| 406 |
+
"""
|
| 407 |
+
name = "complex_elements"
|
| 408 |
+
handler = Dispatcher("ComplexElementsHandler", doc="Handler for key 'complex_elements'.")
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
class SingularPredicate(Predicate):
|
| 412 |
+
"""
|
| 413 |
+
Singular matrix predicate.
|
| 414 |
+
|
| 415 |
+
A matrix is singular iff the value of its determinant is 0.
|
| 416 |
+
|
| 417 |
+
Examples
|
| 418 |
+
========
|
| 419 |
+
|
| 420 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 421 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 422 |
+
>>> ask(Q.singular(X), Q.invertible(X))
|
| 423 |
+
False
|
| 424 |
+
>>> ask(Q.singular(X), ~Q.invertible(X))
|
| 425 |
+
True
|
| 426 |
+
|
| 427 |
+
References
|
| 428 |
+
==========
|
| 429 |
+
|
| 430 |
+
.. [1] https://mathworld.wolfram.com/SingularMatrix.html
|
| 431 |
+
|
| 432 |
+
"""
|
| 433 |
+
name = "singular"
|
| 434 |
+
handler = Dispatcher("SingularHandler", doc="Predicate fore key 'singular'.")
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
class NormalPredicate(Predicate):
|
| 438 |
+
"""
|
| 439 |
+
Normal matrix predicate.
|
| 440 |
+
|
| 441 |
+
A matrix is normal if it commutes with its conjugate transpose.
|
| 442 |
+
|
| 443 |
+
Examples
|
| 444 |
+
========
|
| 445 |
+
|
| 446 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 447 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 448 |
+
>>> ask(Q.normal(X), Q.unitary(X))
|
| 449 |
+
True
|
| 450 |
+
|
| 451 |
+
References
|
| 452 |
+
==========
|
| 453 |
+
|
| 454 |
+
.. [1] https://en.wikipedia.org/wiki/Normal_matrix
|
| 455 |
+
|
| 456 |
+
"""
|
| 457 |
+
name = "normal"
|
| 458 |
+
handler = Dispatcher("NormalHandler", doc="Predicate fore key 'normal'.")
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
class TriangularPredicate(Predicate):
|
| 462 |
+
"""
|
| 463 |
+
Triangular matrix predicate.
|
| 464 |
+
|
| 465 |
+
Explanation
|
| 466 |
+
===========
|
| 467 |
+
|
| 468 |
+
``Q.triangular(X)`` is true if ``X`` is one that is either lower
|
| 469 |
+
triangular or upper triangular.
|
| 470 |
+
|
| 471 |
+
Examples
|
| 472 |
+
========
|
| 473 |
+
|
| 474 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 475 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 476 |
+
>>> ask(Q.triangular(X), Q.upper_triangular(X))
|
| 477 |
+
True
|
| 478 |
+
>>> ask(Q.triangular(X), Q.lower_triangular(X))
|
| 479 |
+
True
|
| 480 |
+
|
| 481 |
+
References
|
| 482 |
+
==========
|
| 483 |
+
|
| 484 |
+
.. [1] https://en.wikipedia.org/wiki/Triangular_matrix
|
| 485 |
+
|
| 486 |
+
"""
|
| 487 |
+
name = "triangular"
|
| 488 |
+
handler = Dispatcher("TriangularHandler", doc="Predicate fore key 'triangular'.")
|
| 489 |
+
|
| 490 |
+
|
| 491 |
+
class UnitTriangularPredicate(Predicate):
|
| 492 |
+
"""
|
| 493 |
+
Unit triangular matrix predicate.
|
| 494 |
+
|
| 495 |
+
Explanation
|
| 496 |
+
===========
|
| 497 |
+
|
| 498 |
+
A unit triangular matrix is a triangular matrix with 1s
|
| 499 |
+
on the diagonal.
|
| 500 |
+
|
| 501 |
+
Examples
|
| 502 |
+
========
|
| 503 |
+
|
| 504 |
+
>>> from sympy import Q, ask, MatrixSymbol
|
| 505 |
+
>>> X = MatrixSymbol('X', 4, 4)
|
| 506 |
+
>>> ask(Q.triangular(X), Q.unit_triangular(X))
|
| 507 |
+
True
|
| 508 |
+
|
| 509 |
+
"""
|
| 510 |
+
name = "unit_triangular"
|
| 511 |
+
handler = Dispatcher("UnitTriangularHandler", doc="Predicate fore key 'unit_triangular'.")
|
lib/python3.12/site-packages/sympy/assumptions/predicates/ntheory.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate
|
| 2 |
+
from sympy.multipledispatch import Dispatcher
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class PrimePredicate(Predicate):
|
| 6 |
+
"""
|
| 7 |
+
Prime number predicate.
|
| 8 |
+
|
| 9 |
+
Explanation
|
| 10 |
+
===========
|
| 11 |
+
|
| 12 |
+
``ask(Q.prime(x))`` is true iff ``x`` is a natural number greater
|
| 13 |
+
than 1 that has no positive divisors other than ``1`` and the
|
| 14 |
+
number itself.
|
| 15 |
+
|
| 16 |
+
Examples
|
| 17 |
+
========
|
| 18 |
+
|
| 19 |
+
>>> from sympy import Q, ask
|
| 20 |
+
>>> ask(Q.prime(0))
|
| 21 |
+
False
|
| 22 |
+
>>> ask(Q.prime(1))
|
| 23 |
+
False
|
| 24 |
+
>>> ask(Q.prime(2))
|
| 25 |
+
True
|
| 26 |
+
>>> ask(Q.prime(20))
|
| 27 |
+
False
|
| 28 |
+
>>> ask(Q.prime(-3))
|
| 29 |
+
False
|
| 30 |
+
|
| 31 |
+
"""
|
| 32 |
+
name = 'prime'
|
| 33 |
+
handler = Dispatcher(
|
| 34 |
+
"PrimeHandler",
|
| 35 |
+
doc=("Handler for key 'prime'. Test that an expression represents a prime"
|
| 36 |
+
" number. When the expression is an exact number, the result (when True)"
|
| 37 |
+
" is subject to the limitations of isprime() which is used to return the "
|
| 38 |
+
"result.")
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class CompositePredicate(Predicate):
|
| 43 |
+
"""
|
| 44 |
+
Composite number predicate.
|
| 45 |
+
|
| 46 |
+
Explanation
|
| 47 |
+
===========
|
| 48 |
+
|
| 49 |
+
``ask(Q.composite(x))`` is true iff ``x`` is a positive integer and has
|
| 50 |
+
at least one positive divisor other than ``1`` and the number itself.
|
| 51 |
+
|
| 52 |
+
Examples
|
| 53 |
+
========
|
| 54 |
+
|
| 55 |
+
>>> from sympy import Q, ask
|
| 56 |
+
>>> ask(Q.composite(0))
|
| 57 |
+
False
|
| 58 |
+
>>> ask(Q.composite(1))
|
| 59 |
+
False
|
| 60 |
+
>>> ask(Q.composite(2))
|
| 61 |
+
False
|
| 62 |
+
>>> ask(Q.composite(20))
|
| 63 |
+
True
|
| 64 |
+
|
| 65 |
+
"""
|
| 66 |
+
name = 'composite'
|
| 67 |
+
handler = Dispatcher("CompositeHandler", doc="Handler for key 'composite'.")
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
class EvenPredicate(Predicate):
|
| 71 |
+
"""
|
| 72 |
+
Even number predicate.
|
| 73 |
+
|
| 74 |
+
Explanation
|
| 75 |
+
===========
|
| 76 |
+
|
| 77 |
+
``ask(Q.even(x))`` is true iff ``x`` belongs to the set of even
|
| 78 |
+
integers.
|
| 79 |
+
|
| 80 |
+
Examples
|
| 81 |
+
========
|
| 82 |
+
|
| 83 |
+
>>> from sympy import Q, ask, pi
|
| 84 |
+
>>> ask(Q.even(0))
|
| 85 |
+
True
|
| 86 |
+
>>> ask(Q.even(2))
|
| 87 |
+
True
|
| 88 |
+
>>> ask(Q.even(3))
|
| 89 |
+
False
|
| 90 |
+
>>> ask(Q.even(pi))
|
| 91 |
+
False
|
| 92 |
+
|
| 93 |
+
"""
|
| 94 |
+
name = 'even'
|
| 95 |
+
handler = Dispatcher("EvenHandler", doc="Handler for key 'even'.")
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
class OddPredicate(Predicate):
|
| 99 |
+
"""
|
| 100 |
+
Odd number predicate.
|
| 101 |
+
|
| 102 |
+
Explanation
|
| 103 |
+
===========
|
| 104 |
+
|
| 105 |
+
``ask(Q.odd(x))`` is true iff ``x`` belongs to the set of odd numbers.
|
| 106 |
+
|
| 107 |
+
Examples
|
| 108 |
+
========
|
| 109 |
+
|
| 110 |
+
>>> from sympy import Q, ask, pi
|
| 111 |
+
>>> ask(Q.odd(0))
|
| 112 |
+
False
|
| 113 |
+
>>> ask(Q.odd(2))
|
| 114 |
+
False
|
| 115 |
+
>>> ask(Q.odd(3))
|
| 116 |
+
True
|
| 117 |
+
>>> ask(Q.odd(pi))
|
| 118 |
+
False
|
| 119 |
+
|
| 120 |
+
"""
|
| 121 |
+
name = 'odd'
|
| 122 |
+
handler = Dispatcher(
|
| 123 |
+
"OddHandler",
|
| 124 |
+
doc=("Handler for key 'odd'. Test that an expression represents an odd"
|
| 125 |
+
" number.")
|
| 126 |
+
)
|
lib/python3.12/site-packages/sympy/assumptions/predicates/order.py
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate
|
| 2 |
+
from sympy.multipledispatch import Dispatcher
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class NegativePredicate(Predicate):
|
| 6 |
+
r"""
|
| 7 |
+
Negative number predicate.
|
| 8 |
+
|
| 9 |
+
Explanation
|
| 10 |
+
===========
|
| 11 |
+
|
| 12 |
+
``Q.negative(x)`` is true iff ``x`` is a real number and :math:`x < 0`, that is,
|
| 13 |
+
it is in the interval :math:`(-\infty, 0)`. Note in particular that negative
|
| 14 |
+
infinity is not negative.
|
| 15 |
+
|
| 16 |
+
A few important facts about negative numbers:
|
| 17 |
+
|
| 18 |
+
- Note that ``Q.nonnegative`` and ``~Q.negative`` are *not* the same
|
| 19 |
+
thing. ``~Q.negative(x)`` simply means that ``x`` is not negative,
|
| 20 |
+
whereas ``Q.nonnegative(x)`` means that ``x`` is real and not
|
| 21 |
+
negative, i.e., ``Q.nonnegative(x)`` is logically equivalent to
|
| 22 |
+
``Q.zero(x) | Q.positive(x)``. So for example, ``~Q.negative(I)`` is
|
| 23 |
+
true, whereas ``Q.nonnegative(I)`` is false.
|
| 24 |
+
|
| 25 |
+
- See the documentation of ``Q.real`` for more information about
|
| 26 |
+
related facts.
|
| 27 |
+
|
| 28 |
+
Examples
|
| 29 |
+
========
|
| 30 |
+
|
| 31 |
+
>>> from sympy import Q, ask, symbols, I
|
| 32 |
+
>>> x = symbols('x')
|
| 33 |
+
>>> ask(Q.negative(x), Q.real(x) & ~Q.positive(x) & ~Q.zero(x))
|
| 34 |
+
True
|
| 35 |
+
>>> ask(Q.negative(-1))
|
| 36 |
+
True
|
| 37 |
+
>>> ask(Q.nonnegative(I))
|
| 38 |
+
False
|
| 39 |
+
>>> ask(~Q.negative(I))
|
| 40 |
+
True
|
| 41 |
+
|
| 42 |
+
"""
|
| 43 |
+
name = 'negative'
|
| 44 |
+
handler = Dispatcher(
|
| 45 |
+
"NegativeHandler",
|
| 46 |
+
doc=("Handler for Q.negative. Test that an expression is strictly less"
|
| 47 |
+
" than zero.")
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class NonNegativePredicate(Predicate):
|
| 52 |
+
"""
|
| 53 |
+
Nonnegative real number predicate.
|
| 54 |
+
|
| 55 |
+
Explanation
|
| 56 |
+
===========
|
| 57 |
+
|
| 58 |
+
``ask(Q.nonnegative(x))`` is true iff ``x`` belongs to the set of
|
| 59 |
+
positive numbers including zero.
|
| 60 |
+
|
| 61 |
+
- Note that ``Q.nonnegative`` and ``~Q.negative`` are *not* the same
|
| 62 |
+
thing. ``~Q.negative(x)`` simply means that ``x`` is not negative,
|
| 63 |
+
whereas ``Q.nonnegative(x)`` means that ``x`` is real and not
|
| 64 |
+
negative, i.e., ``Q.nonnegative(x)`` is logically equivalent to
|
| 65 |
+
``Q.zero(x) | Q.positive(x)``. So for example, ``~Q.negative(I)`` is
|
| 66 |
+
true, whereas ``Q.nonnegative(I)`` is false.
|
| 67 |
+
|
| 68 |
+
Examples
|
| 69 |
+
========
|
| 70 |
+
|
| 71 |
+
>>> from sympy import Q, ask, I
|
| 72 |
+
>>> ask(Q.nonnegative(1))
|
| 73 |
+
True
|
| 74 |
+
>>> ask(Q.nonnegative(0))
|
| 75 |
+
True
|
| 76 |
+
>>> ask(Q.nonnegative(-1))
|
| 77 |
+
False
|
| 78 |
+
>>> ask(Q.nonnegative(I))
|
| 79 |
+
False
|
| 80 |
+
>>> ask(Q.nonnegative(-I))
|
| 81 |
+
False
|
| 82 |
+
|
| 83 |
+
"""
|
| 84 |
+
name = 'nonnegative'
|
| 85 |
+
handler = Dispatcher(
|
| 86 |
+
"NonNegativeHandler",
|
| 87 |
+
doc=("Handler for Q.nonnegative.")
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
class NonZeroPredicate(Predicate):
|
| 92 |
+
"""
|
| 93 |
+
Nonzero real number predicate.
|
| 94 |
+
|
| 95 |
+
Explanation
|
| 96 |
+
===========
|
| 97 |
+
|
| 98 |
+
``ask(Q.nonzero(x))`` is true iff ``x`` is real and ``x`` is not zero. Note in
|
| 99 |
+
particular that ``Q.nonzero(x)`` is false if ``x`` is not real. Use
|
| 100 |
+
``~Q.zero(x)`` if you want the negation of being zero without any real
|
| 101 |
+
assumptions.
|
| 102 |
+
|
| 103 |
+
A few important facts about nonzero numbers:
|
| 104 |
+
|
| 105 |
+
- ``Q.nonzero`` is logically equivalent to ``Q.positive | Q.negative``.
|
| 106 |
+
|
| 107 |
+
- See the documentation of ``Q.real`` for more information about
|
| 108 |
+
related facts.
|
| 109 |
+
|
| 110 |
+
Examples
|
| 111 |
+
========
|
| 112 |
+
|
| 113 |
+
>>> from sympy import Q, ask, symbols, I, oo
|
| 114 |
+
>>> x = symbols('x')
|
| 115 |
+
>>> print(ask(Q.nonzero(x), ~Q.zero(x)))
|
| 116 |
+
None
|
| 117 |
+
>>> ask(Q.nonzero(x), Q.positive(x))
|
| 118 |
+
True
|
| 119 |
+
>>> ask(Q.nonzero(x), Q.zero(x))
|
| 120 |
+
False
|
| 121 |
+
>>> ask(Q.nonzero(0))
|
| 122 |
+
False
|
| 123 |
+
>>> ask(Q.nonzero(I))
|
| 124 |
+
False
|
| 125 |
+
>>> ask(~Q.zero(I))
|
| 126 |
+
True
|
| 127 |
+
>>> ask(Q.nonzero(oo))
|
| 128 |
+
False
|
| 129 |
+
|
| 130 |
+
"""
|
| 131 |
+
name = 'nonzero'
|
| 132 |
+
handler = Dispatcher(
|
| 133 |
+
"NonZeroHandler",
|
| 134 |
+
doc=("Handler for key 'nonzero'. Test that an expression is not identically"
|
| 135 |
+
" zero.")
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class ZeroPredicate(Predicate):
|
| 140 |
+
"""
|
| 141 |
+
Zero number predicate.
|
| 142 |
+
|
| 143 |
+
Explanation
|
| 144 |
+
===========
|
| 145 |
+
|
| 146 |
+
``ask(Q.zero(x))`` is true iff the value of ``x`` is zero.
|
| 147 |
+
|
| 148 |
+
Examples
|
| 149 |
+
========
|
| 150 |
+
|
| 151 |
+
>>> from sympy import ask, Q, oo, symbols
|
| 152 |
+
>>> x, y = symbols('x, y')
|
| 153 |
+
>>> ask(Q.zero(0))
|
| 154 |
+
True
|
| 155 |
+
>>> ask(Q.zero(1/oo))
|
| 156 |
+
True
|
| 157 |
+
>>> print(ask(Q.zero(0*oo)))
|
| 158 |
+
None
|
| 159 |
+
>>> ask(Q.zero(1))
|
| 160 |
+
False
|
| 161 |
+
>>> ask(Q.zero(x*y), Q.zero(x) | Q.zero(y))
|
| 162 |
+
True
|
| 163 |
+
|
| 164 |
+
"""
|
| 165 |
+
name = 'zero'
|
| 166 |
+
handler = Dispatcher(
|
| 167 |
+
"ZeroHandler",
|
| 168 |
+
doc="Handler for key 'zero'."
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
class NonPositivePredicate(Predicate):
|
| 173 |
+
"""
|
| 174 |
+
Nonpositive real number predicate.
|
| 175 |
+
|
| 176 |
+
Explanation
|
| 177 |
+
===========
|
| 178 |
+
|
| 179 |
+
``ask(Q.nonpositive(x))`` is true iff ``x`` belongs to the set of
|
| 180 |
+
negative numbers including zero.
|
| 181 |
+
|
| 182 |
+
- Note that ``Q.nonpositive`` and ``~Q.positive`` are *not* the same
|
| 183 |
+
thing. ``~Q.positive(x)`` simply means that ``x`` is not positive,
|
| 184 |
+
whereas ``Q.nonpositive(x)`` means that ``x`` is real and not
|
| 185 |
+
positive, i.e., ``Q.nonpositive(x)`` is logically equivalent to
|
| 186 |
+
`Q.negative(x) | Q.zero(x)``. So for example, ``~Q.positive(I)`` is
|
| 187 |
+
true, whereas ``Q.nonpositive(I)`` is false.
|
| 188 |
+
|
| 189 |
+
Examples
|
| 190 |
+
========
|
| 191 |
+
|
| 192 |
+
>>> from sympy import Q, ask, I
|
| 193 |
+
|
| 194 |
+
>>> ask(Q.nonpositive(-1))
|
| 195 |
+
True
|
| 196 |
+
>>> ask(Q.nonpositive(0))
|
| 197 |
+
True
|
| 198 |
+
>>> ask(Q.nonpositive(1))
|
| 199 |
+
False
|
| 200 |
+
>>> ask(Q.nonpositive(I))
|
| 201 |
+
False
|
| 202 |
+
>>> ask(Q.nonpositive(-I))
|
| 203 |
+
False
|
| 204 |
+
|
| 205 |
+
"""
|
| 206 |
+
name = 'nonpositive'
|
| 207 |
+
handler = Dispatcher(
|
| 208 |
+
"NonPositiveHandler",
|
| 209 |
+
doc="Handler for key 'nonpositive'."
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
class PositivePredicate(Predicate):
|
| 214 |
+
r"""
|
| 215 |
+
Positive real number predicate.
|
| 216 |
+
|
| 217 |
+
Explanation
|
| 218 |
+
===========
|
| 219 |
+
|
| 220 |
+
``Q.positive(x)`` is true iff ``x`` is real and `x > 0`, that is if ``x``
|
| 221 |
+
is in the interval `(0, \infty)`. In particular, infinity is not
|
| 222 |
+
positive.
|
| 223 |
+
|
| 224 |
+
A few important facts about positive numbers:
|
| 225 |
+
|
| 226 |
+
- Note that ``Q.nonpositive`` and ``~Q.positive`` are *not* the same
|
| 227 |
+
thing. ``~Q.positive(x)`` simply means that ``x`` is not positive,
|
| 228 |
+
whereas ``Q.nonpositive(x)`` means that ``x`` is real and not
|
| 229 |
+
positive, i.e., ``Q.nonpositive(x)`` is logically equivalent to
|
| 230 |
+
`Q.negative(x) | Q.zero(x)``. So for example, ``~Q.positive(I)`` is
|
| 231 |
+
true, whereas ``Q.nonpositive(I)`` is false.
|
| 232 |
+
|
| 233 |
+
- See the documentation of ``Q.real`` for more information about
|
| 234 |
+
related facts.
|
| 235 |
+
|
| 236 |
+
Examples
|
| 237 |
+
========
|
| 238 |
+
|
| 239 |
+
>>> from sympy import Q, ask, symbols, I
|
| 240 |
+
>>> x = symbols('x')
|
| 241 |
+
>>> ask(Q.positive(x), Q.real(x) & ~Q.negative(x) & ~Q.zero(x))
|
| 242 |
+
True
|
| 243 |
+
>>> ask(Q.positive(1))
|
| 244 |
+
True
|
| 245 |
+
>>> ask(Q.nonpositive(I))
|
| 246 |
+
False
|
| 247 |
+
>>> ask(~Q.positive(I))
|
| 248 |
+
True
|
| 249 |
+
|
| 250 |
+
"""
|
| 251 |
+
name = 'positive'
|
| 252 |
+
handler = Dispatcher(
|
| 253 |
+
"PositiveHandler",
|
| 254 |
+
doc=("Handler for key 'positive'. Test that an expression is strictly"
|
| 255 |
+
" greater than zero.")
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
class ExtendedPositivePredicate(Predicate):
|
| 260 |
+
r"""
|
| 261 |
+
Positive extended real number predicate.
|
| 262 |
+
|
| 263 |
+
Explanation
|
| 264 |
+
===========
|
| 265 |
+
|
| 266 |
+
``Q.extended_positive(x)`` is true iff ``x`` is extended real and
|
| 267 |
+
`x > 0`, that is if ``x`` is in the interval `(0, \infty]`.
|
| 268 |
+
|
| 269 |
+
Examples
|
| 270 |
+
========
|
| 271 |
+
|
| 272 |
+
>>> from sympy import ask, I, oo, Q
|
| 273 |
+
>>> ask(Q.extended_positive(1))
|
| 274 |
+
True
|
| 275 |
+
>>> ask(Q.extended_positive(oo))
|
| 276 |
+
True
|
| 277 |
+
>>> ask(Q.extended_positive(I))
|
| 278 |
+
False
|
| 279 |
+
|
| 280 |
+
"""
|
| 281 |
+
name = 'extended_positive'
|
| 282 |
+
handler = Dispatcher("ExtendedPositiveHandler")
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
class ExtendedNegativePredicate(Predicate):
|
| 286 |
+
r"""
|
| 287 |
+
Negative extended real number predicate.
|
| 288 |
+
|
| 289 |
+
Explanation
|
| 290 |
+
===========
|
| 291 |
+
|
| 292 |
+
``Q.extended_negative(x)`` is true iff ``x`` is extended real and
|
| 293 |
+
`x < 0`, that is if ``x`` is in the interval `[-\infty, 0)`.
|
| 294 |
+
|
| 295 |
+
Examples
|
| 296 |
+
========
|
| 297 |
+
|
| 298 |
+
>>> from sympy import ask, I, oo, Q
|
| 299 |
+
>>> ask(Q.extended_negative(-1))
|
| 300 |
+
True
|
| 301 |
+
>>> ask(Q.extended_negative(-oo))
|
| 302 |
+
True
|
| 303 |
+
>>> ask(Q.extended_negative(-I))
|
| 304 |
+
False
|
| 305 |
+
|
| 306 |
+
"""
|
| 307 |
+
name = 'extended_negative'
|
| 308 |
+
handler = Dispatcher("ExtendedNegativeHandler")
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
class ExtendedNonZeroPredicate(Predicate):
|
| 312 |
+
"""
|
| 313 |
+
Nonzero extended real number predicate.
|
| 314 |
+
|
| 315 |
+
Explanation
|
| 316 |
+
===========
|
| 317 |
+
|
| 318 |
+
``ask(Q.extended_nonzero(x))`` is true iff ``x`` is extended real and
|
| 319 |
+
``x`` is not zero.
|
| 320 |
+
|
| 321 |
+
Examples
|
| 322 |
+
========
|
| 323 |
+
|
| 324 |
+
>>> from sympy import ask, I, oo, Q
|
| 325 |
+
>>> ask(Q.extended_nonzero(-1))
|
| 326 |
+
True
|
| 327 |
+
>>> ask(Q.extended_nonzero(oo))
|
| 328 |
+
True
|
| 329 |
+
>>> ask(Q.extended_nonzero(I))
|
| 330 |
+
False
|
| 331 |
+
|
| 332 |
+
"""
|
| 333 |
+
name = 'extended_nonzero'
|
| 334 |
+
handler = Dispatcher("ExtendedNonZeroHandler")
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
class ExtendedNonPositivePredicate(Predicate):
|
| 338 |
+
"""
|
| 339 |
+
Nonpositive extended real number predicate.
|
| 340 |
+
|
| 341 |
+
Explanation
|
| 342 |
+
===========
|
| 343 |
+
|
| 344 |
+
``ask(Q.extended_nonpositive(x))`` is true iff ``x`` is extended real and
|
| 345 |
+
``x`` is not positive.
|
| 346 |
+
|
| 347 |
+
Examples
|
| 348 |
+
========
|
| 349 |
+
|
| 350 |
+
>>> from sympy import ask, I, oo, Q
|
| 351 |
+
>>> ask(Q.extended_nonpositive(-1))
|
| 352 |
+
True
|
| 353 |
+
>>> ask(Q.extended_nonpositive(oo))
|
| 354 |
+
False
|
| 355 |
+
>>> ask(Q.extended_nonpositive(0))
|
| 356 |
+
True
|
| 357 |
+
>>> ask(Q.extended_nonpositive(I))
|
| 358 |
+
False
|
| 359 |
+
|
| 360 |
+
"""
|
| 361 |
+
name = 'extended_nonpositive'
|
| 362 |
+
handler = Dispatcher("ExtendedNonPositiveHandler")
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
class ExtendedNonNegativePredicate(Predicate):
|
| 366 |
+
"""
|
| 367 |
+
Nonnegative extended real number predicate.
|
| 368 |
+
|
| 369 |
+
Explanation
|
| 370 |
+
===========
|
| 371 |
+
|
| 372 |
+
``ask(Q.extended_nonnegative(x))`` is true iff ``x`` is extended real and
|
| 373 |
+
``x`` is not negative.
|
| 374 |
+
|
| 375 |
+
Examples
|
| 376 |
+
========
|
| 377 |
+
|
| 378 |
+
>>> from sympy import ask, I, oo, Q
|
| 379 |
+
>>> ask(Q.extended_nonnegative(-1))
|
| 380 |
+
False
|
| 381 |
+
>>> ask(Q.extended_nonnegative(oo))
|
| 382 |
+
True
|
| 383 |
+
>>> ask(Q.extended_nonnegative(0))
|
| 384 |
+
True
|
| 385 |
+
>>> ask(Q.extended_nonnegative(I))
|
| 386 |
+
False
|
| 387 |
+
|
| 388 |
+
"""
|
| 389 |
+
name = 'extended_nonnegative'
|
| 390 |
+
handler = Dispatcher("ExtendedNonNegativeHandler")
|
lib/python3.12/site-packages/sympy/assumptions/predicates/sets.py
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.assumptions import Predicate
|
| 2 |
+
from sympy.multipledispatch import Dispatcher
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class IntegerPredicate(Predicate):
|
| 6 |
+
"""
|
| 7 |
+
Integer predicate.
|
| 8 |
+
|
| 9 |
+
Explanation
|
| 10 |
+
===========
|
| 11 |
+
|
| 12 |
+
``Q.integer(x)`` is true iff ``x`` belongs to the set of integer
|
| 13 |
+
numbers.
|
| 14 |
+
|
| 15 |
+
Examples
|
| 16 |
+
========
|
| 17 |
+
|
| 18 |
+
>>> from sympy import Q, ask, S
|
| 19 |
+
>>> ask(Q.integer(5))
|
| 20 |
+
True
|
| 21 |
+
>>> ask(Q.integer(S(1)/2))
|
| 22 |
+
False
|
| 23 |
+
|
| 24 |
+
References
|
| 25 |
+
==========
|
| 26 |
+
|
| 27 |
+
.. [1] https://en.wikipedia.org/wiki/Integer
|
| 28 |
+
|
| 29 |
+
"""
|
| 30 |
+
name = 'integer'
|
| 31 |
+
handler = Dispatcher(
|
| 32 |
+
"IntegerHandler",
|
| 33 |
+
doc=("Handler for Q.integer.\n\n"
|
| 34 |
+
"Test that an expression belongs to the field of integer numbers.")
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class NonIntegerPredicate(Predicate):
|
| 39 |
+
"""
|
| 40 |
+
Non-integer extended real predicate.
|
| 41 |
+
"""
|
| 42 |
+
name = 'noninteger'
|
| 43 |
+
handler = Dispatcher(
|
| 44 |
+
"NonIntegerHandler",
|
| 45 |
+
doc=("Handler for Q.noninteger.\n\n"
|
| 46 |
+
"Test that an expression is a non-integer extended real number.")
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class RationalPredicate(Predicate):
|
| 51 |
+
"""
|
| 52 |
+
Rational number predicate.
|
| 53 |
+
|
| 54 |
+
Explanation
|
| 55 |
+
===========
|
| 56 |
+
|
| 57 |
+
``Q.rational(x)`` is true iff ``x`` belongs to the set of
|
| 58 |
+
rational numbers.
|
| 59 |
+
|
| 60 |
+
Examples
|
| 61 |
+
========
|
| 62 |
+
|
| 63 |
+
>>> from sympy import ask, Q, pi, S
|
| 64 |
+
>>> ask(Q.rational(0))
|
| 65 |
+
True
|
| 66 |
+
>>> ask(Q.rational(S(1)/2))
|
| 67 |
+
True
|
| 68 |
+
>>> ask(Q.rational(pi))
|
| 69 |
+
False
|
| 70 |
+
|
| 71 |
+
References
|
| 72 |
+
==========
|
| 73 |
+
|
| 74 |
+
.. [1] https://en.wikipedia.org/wiki/Rational_number
|
| 75 |
+
|
| 76 |
+
"""
|
| 77 |
+
name = 'rational'
|
| 78 |
+
handler = Dispatcher(
|
| 79 |
+
"RationalHandler",
|
| 80 |
+
doc=("Handler for Q.rational.\n\n"
|
| 81 |
+
"Test that an expression belongs to the field of rational numbers.")
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
class IrrationalPredicate(Predicate):
|
| 86 |
+
"""
|
| 87 |
+
Irrational number predicate.
|
| 88 |
+
|
| 89 |
+
Explanation
|
| 90 |
+
===========
|
| 91 |
+
|
| 92 |
+
``Q.irrational(x)`` is true iff ``x`` is any real number that
|
| 93 |
+
cannot be expressed as a ratio of integers.
|
| 94 |
+
|
| 95 |
+
Examples
|
| 96 |
+
========
|
| 97 |
+
|
| 98 |
+
>>> from sympy import ask, Q, pi, S, I
|
| 99 |
+
>>> ask(Q.irrational(0))
|
| 100 |
+
False
|
| 101 |
+
>>> ask(Q.irrational(S(1)/2))
|
| 102 |
+
False
|
| 103 |
+
>>> ask(Q.irrational(pi))
|
| 104 |
+
True
|
| 105 |
+
>>> ask(Q.irrational(I))
|
| 106 |
+
False
|
| 107 |
+
|
| 108 |
+
References
|
| 109 |
+
==========
|
| 110 |
+
|
| 111 |
+
.. [1] https://en.wikipedia.org/wiki/Irrational_number
|
| 112 |
+
|
| 113 |
+
"""
|
| 114 |
+
name = 'irrational'
|
| 115 |
+
handler = Dispatcher(
|
| 116 |
+
"IrrationalHandler",
|
| 117 |
+
doc=("Handler for Q.irrational.\n\n"
|
| 118 |
+
"Test that an expression is irrational numbers.")
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
class RealPredicate(Predicate):
|
| 123 |
+
r"""
|
| 124 |
+
Real number predicate.
|
| 125 |
+
|
| 126 |
+
Explanation
|
| 127 |
+
===========
|
| 128 |
+
|
| 129 |
+
``Q.real(x)`` is true iff ``x`` is a real number, i.e., it is in the
|
| 130 |
+
interval `(-\infty, \infty)`. Note that, in particular the
|
| 131 |
+
infinities are not real. Use ``Q.extended_real`` if you want to
|
| 132 |
+
consider those as well.
|
| 133 |
+
|
| 134 |
+
A few important facts about reals:
|
| 135 |
+
|
| 136 |
+
- Every real number is positive, negative, or zero. Furthermore,
|
| 137 |
+
because these sets are pairwise disjoint, each real number is
|
| 138 |
+
exactly one of those three.
|
| 139 |
+
|
| 140 |
+
- Every real number is also complex.
|
| 141 |
+
|
| 142 |
+
- Every real number is finite.
|
| 143 |
+
|
| 144 |
+
- Every real number is either rational or irrational.
|
| 145 |
+
|
| 146 |
+
- Every real number is either algebraic or transcendental.
|
| 147 |
+
|
| 148 |
+
- The facts ``Q.negative``, ``Q.zero``, ``Q.positive``,
|
| 149 |
+
``Q.nonnegative``, ``Q.nonpositive``, ``Q.nonzero``,
|
| 150 |
+
``Q.integer``, ``Q.rational``, and ``Q.irrational`` all imply
|
| 151 |
+
``Q.real``, as do all facts that imply those facts.
|
| 152 |
+
|
| 153 |
+
- The facts ``Q.algebraic``, and ``Q.transcendental`` do not imply
|
| 154 |
+
``Q.real``; they imply ``Q.complex``. An algebraic or
|
| 155 |
+
transcendental number may or may not be real.
|
| 156 |
+
|
| 157 |
+
- The "non" facts (i.e., ``Q.nonnegative``, ``Q.nonzero``,
|
| 158 |
+
``Q.nonpositive`` and ``Q.noninteger``) are not equivalent to
|
| 159 |
+
not the fact, but rather, not the fact *and* ``Q.real``.
|
| 160 |
+
For example, ``Q.nonnegative`` means ``~Q.negative & Q.real``.
|
| 161 |
+
So for example, ``I`` is not nonnegative, nonzero, or
|
| 162 |
+
nonpositive.
|
| 163 |
+
|
| 164 |
+
Examples
|
| 165 |
+
========
|
| 166 |
+
|
| 167 |
+
>>> from sympy import Q, ask, symbols
|
| 168 |
+
>>> x = symbols('x')
|
| 169 |
+
>>> ask(Q.real(x), Q.positive(x))
|
| 170 |
+
True
|
| 171 |
+
>>> ask(Q.real(0))
|
| 172 |
+
True
|
| 173 |
+
|
| 174 |
+
References
|
| 175 |
+
==========
|
| 176 |
+
|
| 177 |
+
.. [1] https://en.wikipedia.org/wiki/Real_number
|
| 178 |
+
|
| 179 |
+
"""
|
| 180 |
+
name = 'real'
|
| 181 |
+
handler = Dispatcher(
|
| 182 |
+
"RealHandler",
|
| 183 |
+
doc=("Handler for Q.real.\n\n"
|
| 184 |
+
"Test that an expression belongs to the field of real numbers.")
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
class ExtendedRealPredicate(Predicate):
|
| 189 |
+
r"""
|
| 190 |
+
Extended real predicate.
|
| 191 |
+
|
| 192 |
+
Explanation
|
| 193 |
+
===========
|
| 194 |
+
|
| 195 |
+
``Q.extended_real(x)`` is true iff ``x`` is a real number or
|
| 196 |
+
`\{-\infty, \infty\}`.
|
| 197 |
+
|
| 198 |
+
See documentation of ``Q.real`` for more information about related
|
| 199 |
+
facts.
|
| 200 |
+
|
| 201 |
+
Examples
|
| 202 |
+
========
|
| 203 |
+
|
| 204 |
+
>>> from sympy import ask, Q, oo, I
|
| 205 |
+
>>> ask(Q.extended_real(1))
|
| 206 |
+
True
|
| 207 |
+
>>> ask(Q.extended_real(I))
|
| 208 |
+
False
|
| 209 |
+
>>> ask(Q.extended_real(oo))
|
| 210 |
+
True
|
| 211 |
+
|
| 212 |
+
"""
|
| 213 |
+
name = 'extended_real'
|
| 214 |
+
handler = Dispatcher(
|
| 215 |
+
"ExtendedRealHandler",
|
| 216 |
+
doc=("Handler for Q.extended_real.\n\n"
|
| 217 |
+
"Test that an expression belongs to the field of extended real\n"
|
| 218 |
+
"numbers, that is real numbers union {Infinity, -Infinity}.")
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
class HermitianPredicate(Predicate):
|
| 223 |
+
"""
|
| 224 |
+
Hermitian predicate.
|
| 225 |
+
|
| 226 |
+
Explanation
|
| 227 |
+
===========
|
| 228 |
+
|
| 229 |
+
``ask(Q.hermitian(x))`` is true iff ``x`` belongs to the set of
|
| 230 |
+
Hermitian operators.
|
| 231 |
+
|
| 232 |
+
References
|
| 233 |
+
==========
|
| 234 |
+
|
| 235 |
+
.. [1] https://mathworld.wolfram.com/HermitianOperator.html
|
| 236 |
+
|
| 237 |
+
"""
|
| 238 |
+
# TODO: Add examples
|
| 239 |
+
name = 'hermitian'
|
| 240 |
+
handler = Dispatcher(
|
| 241 |
+
"HermitianHandler",
|
| 242 |
+
doc=("Handler for Q.hermitian.\n\n"
|
| 243 |
+
"Test that an expression belongs to the field of Hermitian operators.")
|
| 244 |
+
)
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
class ComplexPredicate(Predicate):
|
| 248 |
+
"""
|
| 249 |
+
Complex number predicate.
|
| 250 |
+
|
| 251 |
+
Explanation
|
| 252 |
+
===========
|
| 253 |
+
|
| 254 |
+
``Q.complex(x)`` is true iff ``x`` belongs to the set of complex
|
| 255 |
+
numbers. Note that every complex number is finite.
|
| 256 |
+
|
| 257 |
+
Examples
|
| 258 |
+
========
|
| 259 |
+
|
| 260 |
+
>>> from sympy import Q, Symbol, ask, I, oo
|
| 261 |
+
>>> x = Symbol('x')
|
| 262 |
+
>>> ask(Q.complex(0))
|
| 263 |
+
True
|
| 264 |
+
>>> ask(Q.complex(2 + 3*I))
|
| 265 |
+
True
|
| 266 |
+
>>> ask(Q.complex(oo))
|
| 267 |
+
False
|
| 268 |
+
|
| 269 |
+
References
|
| 270 |
+
==========
|
| 271 |
+
|
| 272 |
+
.. [1] https://en.wikipedia.org/wiki/Complex_number
|
| 273 |
+
|
| 274 |
+
"""
|
| 275 |
+
name = 'complex'
|
| 276 |
+
handler = Dispatcher(
|
| 277 |
+
"ComplexHandler",
|
| 278 |
+
doc=("Handler for Q.complex.\n\n"
|
| 279 |
+
"Test that an expression belongs to the field of complex numbers.")
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
class ImaginaryPredicate(Predicate):
|
| 284 |
+
"""
|
| 285 |
+
Imaginary number predicate.
|
| 286 |
+
|
| 287 |
+
Explanation
|
| 288 |
+
===========
|
| 289 |
+
|
| 290 |
+
``Q.imaginary(x)`` is true iff ``x`` can be written as a real
|
| 291 |
+
number multiplied by the imaginary unit ``I``. Please note that ``0``
|
| 292 |
+
is not considered to be an imaginary number.
|
| 293 |
+
|
| 294 |
+
Examples
|
| 295 |
+
========
|
| 296 |
+
|
| 297 |
+
>>> from sympy import Q, ask, I
|
| 298 |
+
>>> ask(Q.imaginary(3*I))
|
| 299 |
+
True
|
| 300 |
+
>>> ask(Q.imaginary(2 + 3*I))
|
| 301 |
+
False
|
| 302 |
+
>>> ask(Q.imaginary(0))
|
| 303 |
+
False
|
| 304 |
+
|
| 305 |
+
References
|
| 306 |
+
==========
|
| 307 |
+
|
| 308 |
+
.. [1] https://en.wikipedia.org/wiki/Imaginary_number
|
| 309 |
+
|
| 310 |
+
"""
|
| 311 |
+
name = 'imaginary'
|
| 312 |
+
handler = Dispatcher(
|
| 313 |
+
"ImaginaryHandler",
|
| 314 |
+
doc=("Handler for Q.imaginary.\n\n"
|
| 315 |
+
"Test that an expression belongs to the field of imaginary numbers,\n"
|
| 316 |
+
"that is, numbers in the form x*I, where x is real.")
|
| 317 |
+
)
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
class AntihermitianPredicate(Predicate):
|
| 321 |
+
"""
|
| 322 |
+
Antihermitian predicate.
|
| 323 |
+
|
| 324 |
+
Explanation
|
| 325 |
+
===========
|
| 326 |
+
|
| 327 |
+
``Q.antihermitian(x)`` is true iff ``x`` belongs to the field of
|
| 328 |
+
antihermitian operators, i.e., operators in the form ``x*I``, where
|
| 329 |
+
``x`` is Hermitian.
|
| 330 |
+
|
| 331 |
+
References
|
| 332 |
+
==========
|
| 333 |
+
|
| 334 |
+
.. [1] https://mathworld.wolfram.com/HermitianOperator.html
|
| 335 |
+
|
| 336 |
+
"""
|
| 337 |
+
# TODO: Add examples
|
| 338 |
+
name = 'antihermitian'
|
| 339 |
+
handler = Dispatcher(
|
| 340 |
+
"AntiHermitianHandler",
|
| 341 |
+
doc=("Handler for Q.antihermitian.\n\n"
|
| 342 |
+
"Test that an expression belongs to the field of anti-Hermitian\n"
|
| 343 |
+
"operators, that is, operators in the form x*I, where x is Hermitian.")
|
| 344 |
+
)
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
class AlgebraicPredicate(Predicate):
|
| 348 |
+
r"""
|
| 349 |
+
Algebraic number predicate.
|
| 350 |
+
|
| 351 |
+
Explanation
|
| 352 |
+
===========
|
| 353 |
+
|
| 354 |
+
``Q.algebraic(x)`` is true iff ``x`` belongs to the set of
|
| 355 |
+
algebraic numbers. ``x`` is algebraic if there is some polynomial
|
| 356 |
+
in ``p(x)\in \mathbb\{Q\}[x]`` such that ``p(x) = 0``.
|
| 357 |
+
|
| 358 |
+
Examples
|
| 359 |
+
========
|
| 360 |
+
|
| 361 |
+
>>> from sympy import ask, Q, sqrt, I, pi
|
| 362 |
+
>>> ask(Q.algebraic(sqrt(2)))
|
| 363 |
+
True
|
| 364 |
+
>>> ask(Q.algebraic(I))
|
| 365 |
+
True
|
| 366 |
+
>>> ask(Q.algebraic(pi))
|
| 367 |
+
False
|
| 368 |
+
|
| 369 |
+
References
|
| 370 |
+
==========
|
| 371 |
+
|
| 372 |
+
.. [1] https://en.wikipedia.org/wiki/Algebraic_number
|
| 373 |
+
|
| 374 |
+
"""
|
| 375 |
+
name = 'algebraic'
|
| 376 |
+
AlgebraicHandler = Dispatcher(
|
| 377 |
+
"AlgebraicHandler",
|
| 378 |
+
doc="""Handler for Q.algebraic key."""
|
| 379 |
+
)
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
class TranscendentalPredicate(Predicate):
|
| 383 |
+
"""
|
| 384 |
+
Transcedental number predicate.
|
| 385 |
+
|
| 386 |
+
Explanation
|
| 387 |
+
===========
|
| 388 |
+
|
| 389 |
+
``Q.transcendental(x)`` is true iff ``x`` belongs to the set of
|
| 390 |
+
transcendental numbers. A transcendental number is a real
|
| 391 |
+
or complex number that is not algebraic.
|
| 392 |
+
|
| 393 |
+
"""
|
| 394 |
+
# TODO: Add examples
|
| 395 |
+
name = 'transcendental'
|
| 396 |
+
handler = Dispatcher(
|
| 397 |
+
"Transcendental",
|
| 398 |
+
doc="""Handler for Q.transcendental key."""
|
| 399 |
+
)
|
lib/python3.12/site-packages/sympy/parsing/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (342 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/__pycache__/ast_parser.cpython-312.pyc
ADDED
|
Binary file (4.39 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/__pycache__/mathematica.cpython-312.pyc
ADDED
|
Binary file (44.7 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/__pycache__/maxima.cpython-312.pyc
ADDED
|
Binary file (3.9 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/c/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""Used for translating C source code into a SymPy expression"""
|
lib/python3.12/site-packages/sympy/parsing/c/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (267 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/c/__pycache__/c_parser.cpython-312.pyc
ADDED
|
Binary file (42.1 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/c/c_parser.py
ADDED
|
@@ -0,0 +1,1058 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.external import import_module
|
| 2 |
+
import os
|
| 3 |
+
|
| 4 |
+
cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']})
|
| 5 |
+
|
| 6 |
+
"""
|
| 7 |
+
This module contains all the necessary Classes and Function used to Parse C and
|
| 8 |
+
C++ code into SymPy expression
|
| 9 |
+
The module serves as a backend for SymPyExpression to parse C code
|
| 10 |
+
It is also dependent on Clang's AST and SymPy's Codegen AST.
|
| 11 |
+
The module only supports the features currently supported by the Clang and
|
| 12 |
+
codegen AST which will be updated as the development of codegen AST and this
|
| 13 |
+
module progresses.
|
| 14 |
+
You might find unexpected bugs and exceptions while using the module, feel free
|
| 15 |
+
to report them to the SymPy Issue Tracker
|
| 16 |
+
|
| 17 |
+
Features Supported
|
| 18 |
+
==================
|
| 19 |
+
|
| 20 |
+
- Variable Declarations (integers and reals)
|
| 21 |
+
- Assignment (using integer & floating literal and function calls)
|
| 22 |
+
- Function Definitions and Declaration
|
| 23 |
+
- Function Calls
|
| 24 |
+
- Compound statements, Return statements
|
| 25 |
+
|
| 26 |
+
Notes
|
| 27 |
+
=====
|
| 28 |
+
|
| 29 |
+
The module is dependent on an external dependency which needs to be installed
|
| 30 |
+
to use the features of this module.
|
| 31 |
+
|
| 32 |
+
Clang: The C and C++ compiler which is used to extract an AST from the provided
|
| 33 |
+
C source code.
|
| 34 |
+
|
| 35 |
+
References
|
| 36 |
+
==========
|
| 37 |
+
|
| 38 |
+
.. [1] https://github.com/sympy/sympy/issues
|
| 39 |
+
.. [2] https://clang.llvm.org/docs/
|
| 40 |
+
.. [3] https://clang.llvm.org/docs/IntroductionToTheClangAST.html
|
| 41 |
+
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
if cin:
|
| 45 |
+
from sympy.codegen.ast import (Variable, Integer, Float,
|
| 46 |
+
FunctionPrototype, FunctionDefinition, FunctionCall,
|
| 47 |
+
none, Return, Assignment, intc, int8, int16, int64,
|
| 48 |
+
uint8, uint16, uint32, uint64, float32, float64, float80,
|
| 49 |
+
aug_assign, bool_, While, CodeBlock)
|
| 50 |
+
from sympy.codegen.cnodes import (PreDecrement, PostDecrement,
|
| 51 |
+
PreIncrement, PostIncrement)
|
| 52 |
+
from sympy.core import Add, Mod, Mul, Pow, Rel
|
| 53 |
+
from sympy.logic.boolalg import And, as_Boolean, Not, Or
|
| 54 |
+
from sympy.core.symbol import Symbol
|
| 55 |
+
from sympy.core.sympify import sympify
|
| 56 |
+
from sympy.logic.boolalg import (false, true)
|
| 57 |
+
import sys
|
| 58 |
+
import tempfile
|
| 59 |
+
|
| 60 |
+
class BaseParser:
|
| 61 |
+
"""Base Class for the C parser"""
|
| 62 |
+
|
| 63 |
+
def __init__(self):
|
| 64 |
+
"""Initializes the Base parser creating a Clang AST index"""
|
| 65 |
+
self.index = cin.Index.create()
|
| 66 |
+
|
| 67 |
+
def diagnostics(self, out):
|
| 68 |
+
"""Diagostics function for the Clang AST"""
|
| 69 |
+
for diag in self.tu.diagnostics:
|
| 70 |
+
# tu = translation unit
|
| 71 |
+
print('%s %s (line %s, col %s) %s' % (
|
| 72 |
+
{
|
| 73 |
+
4: 'FATAL',
|
| 74 |
+
3: 'ERROR',
|
| 75 |
+
2: 'WARNING',
|
| 76 |
+
1: 'NOTE',
|
| 77 |
+
0: 'IGNORED',
|
| 78 |
+
}[diag.severity],
|
| 79 |
+
diag.location.file,
|
| 80 |
+
diag.location.line,
|
| 81 |
+
diag.location.column,
|
| 82 |
+
diag.spelling
|
| 83 |
+
), file=out)
|
| 84 |
+
|
| 85 |
+
class CCodeConverter(BaseParser):
|
| 86 |
+
"""The Code Convereter for Clang AST
|
| 87 |
+
|
| 88 |
+
The converter object takes the C source code or file as input and
|
| 89 |
+
converts them to SymPy Expressions.
|
| 90 |
+
"""
|
| 91 |
+
|
| 92 |
+
def __init__(self):
|
| 93 |
+
"""Initializes the code converter"""
|
| 94 |
+
super().__init__()
|
| 95 |
+
self._py_nodes = []
|
| 96 |
+
self._data_types = {
|
| 97 |
+
"void": {
|
| 98 |
+
cin.TypeKind.VOID: none
|
| 99 |
+
},
|
| 100 |
+
"bool": {
|
| 101 |
+
cin.TypeKind.BOOL: bool_
|
| 102 |
+
},
|
| 103 |
+
"int": {
|
| 104 |
+
cin.TypeKind.SCHAR: int8,
|
| 105 |
+
cin.TypeKind.SHORT: int16,
|
| 106 |
+
cin.TypeKind.INT: intc,
|
| 107 |
+
cin.TypeKind.LONG: int64,
|
| 108 |
+
cin.TypeKind.UCHAR: uint8,
|
| 109 |
+
cin.TypeKind.USHORT: uint16,
|
| 110 |
+
cin.TypeKind.UINT: uint32,
|
| 111 |
+
cin.TypeKind.ULONG: uint64
|
| 112 |
+
},
|
| 113 |
+
"float": {
|
| 114 |
+
cin.TypeKind.FLOAT: float32,
|
| 115 |
+
cin.TypeKind.DOUBLE: float64,
|
| 116 |
+
cin.TypeKind.LONGDOUBLE: float80
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
def parse(self, filename, flags):
|
| 121 |
+
"""Function to parse a file with C source code
|
| 122 |
+
|
| 123 |
+
It takes the filename as an attribute and creates a Clang AST
|
| 124 |
+
Translation Unit parsing the file.
|
| 125 |
+
Then the transformation function is called on the translation unit,
|
| 126 |
+
whose reults are collected into a list which is returned by the
|
| 127 |
+
function.
|
| 128 |
+
|
| 129 |
+
Parameters
|
| 130 |
+
==========
|
| 131 |
+
|
| 132 |
+
filename : string
|
| 133 |
+
Path to the C file to be parsed
|
| 134 |
+
|
| 135 |
+
flags: list
|
| 136 |
+
Arguments to be passed to Clang while parsing the C code
|
| 137 |
+
|
| 138 |
+
Returns
|
| 139 |
+
=======
|
| 140 |
+
|
| 141 |
+
py_nodes: list
|
| 142 |
+
A list of SymPy AST nodes
|
| 143 |
+
|
| 144 |
+
"""
|
| 145 |
+
filepath = os.path.abspath(filename)
|
| 146 |
+
self.tu = self.index.parse(
|
| 147 |
+
filepath,
|
| 148 |
+
args=flags,
|
| 149 |
+
options=cin.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
|
| 150 |
+
)
|
| 151 |
+
for child in self.tu.cursor.get_children():
|
| 152 |
+
if child.kind == cin.CursorKind.VAR_DECL or child.kind == cin.CursorKind.FUNCTION_DECL:
|
| 153 |
+
self._py_nodes.append(self.transform(child))
|
| 154 |
+
return self._py_nodes
|
| 155 |
+
|
| 156 |
+
def parse_str(self, source, flags):
|
| 157 |
+
"""Function to parse a string with C source code
|
| 158 |
+
|
| 159 |
+
It takes the source code as an attribute, stores it in a temporary
|
| 160 |
+
file and creates a Clang AST Translation Unit parsing the file.
|
| 161 |
+
Then the transformation function is called on the translation unit,
|
| 162 |
+
whose reults are collected into a list which is returned by the
|
| 163 |
+
function.
|
| 164 |
+
|
| 165 |
+
Parameters
|
| 166 |
+
==========
|
| 167 |
+
|
| 168 |
+
source : string
|
| 169 |
+
A string containing the C source code to be parsed
|
| 170 |
+
|
| 171 |
+
flags: list
|
| 172 |
+
Arguments to be passed to Clang while parsing the C code
|
| 173 |
+
|
| 174 |
+
Returns
|
| 175 |
+
=======
|
| 176 |
+
|
| 177 |
+
py_nodes: list
|
| 178 |
+
A list of SymPy AST nodes
|
| 179 |
+
|
| 180 |
+
"""
|
| 181 |
+
file = tempfile.NamedTemporaryFile(mode = 'w+', suffix = '.cpp')
|
| 182 |
+
file.write(source)
|
| 183 |
+
file.seek(0)
|
| 184 |
+
self.tu = self.index.parse(
|
| 185 |
+
file.name,
|
| 186 |
+
args=flags,
|
| 187 |
+
options=cin.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
|
| 188 |
+
)
|
| 189 |
+
file.close()
|
| 190 |
+
for child in self.tu.cursor.get_children():
|
| 191 |
+
if child.kind == cin.CursorKind.VAR_DECL or child.kind == cin.CursorKind.FUNCTION_DECL:
|
| 192 |
+
self._py_nodes.append(self.transform(child))
|
| 193 |
+
return self._py_nodes
|
| 194 |
+
|
| 195 |
+
def transform(self, node):
|
| 196 |
+
"""Transformation Function for Clang AST nodes
|
| 197 |
+
|
| 198 |
+
It determines the kind of node and calls the respective
|
| 199 |
+
transformation function for that node.
|
| 200 |
+
|
| 201 |
+
Raises
|
| 202 |
+
======
|
| 203 |
+
|
| 204 |
+
NotImplementedError : if the transformation for the provided node
|
| 205 |
+
is not implemented
|
| 206 |
+
|
| 207 |
+
"""
|
| 208 |
+
handler = getattr(self, 'transform_%s' % node.kind.name.lower(), None)
|
| 209 |
+
|
| 210 |
+
if handler is None:
|
| 211 |
+
print(
|
| 212 |
+
"Ignoring node of type %s (%s)" % (
|
| 213 |
+
node.kind,
|
| 214 |
+
' '.join(
|
| 215 |
+
t.spelling for t in node.get_tokens())
|
| 216 |
+
),
|
| 217 |
+
file=sys.stderr
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
return handler(node)
|
| 221 |
+
|
| 222 |
+
def transform_var_decl(self, node):
|
| 223 |
+
"""Transformation Function for Variable Declaration
|
| 224 |
+
|
| 225 |
+
Used to create nodes for variable declarations and assignments with
|
| 226 |
+
values or function call for the respective nodes in the clang AST
|
| 227 |
+
|
| 228 |
+
Returns
|
| 229 |
+
=======
|
| 230 |
+
|
| 231 |
+
A variable node as Declaration, with the initial value if given
|
| 232 |
+
|
| 233 |
+
Raises
|
| 234 |
+
======
|
| 235 |
+
|
| 236 |
+
NotImplementedError : if called for data types not currently
|
| 237 |
+
implemented
|
| 238 |
+
|
| 239 |
+
Notes
|
| 240 |
+
=====
|
| 241 |
+
|
| 242 |
+
The function currently supports following data types:
|
| 243 |
+
|
| 244 |
+
Boolean:
|
| 245 |
+
bool, _Bool
|
| 246 |
+
|
| 247 |
+
Integer:
|
| 248 |
+
8-bit: signed char and unsigned char
|
| 249 |
+
16-bit: short, short int, signed short,
|
| 250 |
+
signed short int, unsigned short, unsigned short int
|
| 251 |
+
32-bit: int, signed int, unsigned int
|
| 252 |
+
64-bit: long, long int, signed long,
|
| 253 |
+
signed long int, unsigned long, unsigned long int
|
| 254 |
+
|
| 255 |
+
Floating point:
|
| 256 |
+
Single Precision: float
|
| 257 |
+
Double Precision: double
|
| 258 |
+
Extended Precision: long double
|
| 259 |
+
|
| 260 |
+
"""
|
| 261 |
+
if node.type.kind in self._data_types["int"]:
|
| 262 |
+
type = self._data_types["int"][node.type.kind]
|
| 263 |
+
elif node.type.kind in self._data_types["float"]:
|
| 264 |
+
type = self._data_types["float"][node.type.kind]
|
| 265 |
+
elif node.type.kind in self._data_types["bool"]:
|
| 266 |
+
type = self._data_types["bool"][node.type.kind]
|
| 267 |
+
else:
|
| 268 |
+
raise NotImplementedError("Only bool, int "
|
| 269 |
+
"and float are supported")
|
| 270 |
+
try:
|
| 271 |
+
children = node.get_children()
|
| 272 |
+
child = next(children)
|
| 273 |
+
|
| 274 |
+
#ignoring namespace and type details for the variable
|
| 275 |
+
while child.kind == cin.CursorKind.NAMESPACE_REF or child.kind == cin.CursorKind.TYPE_REF:
|
| 276 |
+
child = next(children)
|
| 277 |
+
|
| 278 |
+
val = self.transform(child)
|
| 279 |
+
|
| 280 |
+
supported_rhs = [
|
| 281 |
+
cin.CursorKind.INTEGER_LITERAL,
|
| 282 |
+
cin.CursorKind.FLOATING_LITERAL,
|
| 283 |
+
cin.CursorKind.UNEXPOSED_EXPR,
|
| 284 |
+
cin.CursorKind.BINARY_OPERATOR,
|
| 285 |
+
cin.CursorKind.PAREN_EXPR,
|
| 286 |
+
cin.CursorKind.UNARY_OPERATOR,
|
| 287 |
+
cin.CursorKind.CXX_BOOL_LITERAL_EXPR
|
| 288 |
+
]
|
| 289 |
+
|
| 290 |
+
if child.kind in supported_rhs:
|
| 291 |
+
if isinstance(val, str):
|
| 292 |
+
value = Symbol(val)
|
| 293 |
+
elif isinstance(val, bool):
|
| 294 |
+
if node.type.kind in self._data_types["int"]:
|
| 295 |
+
value = Integer(0) if val == False else Integer(1)
|
| 296 |
+
elif node.type.kind in self._data_types["float"]:
|
| 297 |
+
value = Float(0.0) if val == False else Float(1.0)
|
| 298 |
+
elif node.type.kind in self._data_types["bool"]:
|
| 299 |
+
value = sympify(val)
|
| 300 |
+
elif isinstance(val, (Integer, int, Float, float)):
|
| 301 |
+
if node.type.kind in self._data_types["int"]:
|
| 302 |
+
value = Integer(val)
|
| 303 |
+
elif node.type.kind in self._data_types["float"]:
|
| 304 |
+
value = Float(val)
|
| 305 |
+
elif node.type.kind in self._data_types["bool"]:
|
| 306 |
+
value = sympify(bool(val))
|
| 307 |
+
else:
|
| 308 |
+
value = val
|
| 309 |
+
|
| 310 |
+
return Variable(
|
| 311 |
+
node.spelling
|
| 312 |
+
).as_Declaration(
|
| 313 |
+
type = type,
|
| 314 |
+
value = value
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
elif child.kind == cin.CursorKind.CALL_EXPR:
|
| 318 |
+
return Variable(
|
| 319 |
+
node.spelling
|
| 320 |
+
).as_Declaration(
|
| 321 |
+
value = val
|
| 322 |
+
)
|
| 323 |
+
|
| 324 |
+
else:
|
| 325 |
+
raise NotImplementedError("Given "
|
| 326 |
+
"variable declaration \"{}\" "
|
| 327 |
+
"is not possible to parse yet!"
|
| 328 |
+
.format(" ".join(
|
| 329 |
+
t.spelling for t in node.get_tokens()
|
| 330 |
+
)
|
| 331 |
+
))
|
| 332 |
+
|
| 333 |
+
except StopIteration:
|
| 334 |
+
return Variable(
|
| 335 |
+
node.spelling
|
| 336 |
+
).as_Declaration(
|
| 337 |
+
type = type
|
| 338 |
+
)
|
| 339 |
+
|
| 340 |
+
def transform_function_decl(self, node):
|
| 341 |
+
"""Transformation Function For Function Declaration
|
| 342 |
+
|
| 343 |
+
Used to create nodes for function declarations and definitions for
|
| 344 |
+
the respective nodes in the clang AST
|
| 345 |
+
|
| 346 |
+
Returns
|
| 347 |
+
=======
|
| 348 |
+
|
| 349 |
+
function : Codegen AST node
|
| 350 |
+
- FunctionPrototype node if function body is not present
|
| 351 |
+
- FunctionDefinition node if the function body is present
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
"""
|
| 355 |
+
|
| 356 |
+
if node.result_type.kind in self._data_types["int"]:
|
| 357 |
+
ret_type = self._data_types["int"][node.result_type.kind]
|
| 358 |
+
elif node.result_type.kind in self._data_types["float"]:
|
| 359 |
+
ret_type = self._data_types["float"][node.result_type.kind]
|
| 360 |
+
elif node.result_type.kind in self._data_types["bool"]:
|
| 361 |
+
ret_type = self._data_types["bool"][node.result_type.kind]
|
| 362 |
+
elif node.result_type.kind in self._data_types["void"]:
|
| 363 |
+
ret_type = self._data_types["void"][node.result_type.kind]
|
| 364 |
+
else:
|
| 365 |
+
raise NotImplementedError("Only void, bool, int "
|
| 366 |
+
"and float are supported")
|
| 367 |
+
body = []
|
| 368 |
+
param = []
|
| 369 |
+
|
| 370 |
+
# Subsequent nodes will be the parameters for the function.
|
| 371 |
+
for child in node.get_children():
|
| 372 |
+
decl = self.transform(child)
|
| 373 |
+
if child.kind == cin.CursorKind.PARM_DECL:
|
| 374 |
+
param.append(decl)
|
| 375 |
+
elif child.kind == cin.CursorKind.COMPOUND_STMT:
|
| 376 |
+
for val in decl:
|
| 377 |
+
body.append(val)
|
| 378 |
+
else:
|
| 379 |
+
body.append(decl)
|
| 380 |
+
|
| 381 |
+
if body == []:
|
| 382 |
+
function = FunctionPrototype(
|
| 383 |
+
return_type = ret_type,
|
| 384 |
+
name = node.spelling,
|
| 385 |
+
parameters = param
|
| 386 |
+
)
|
| 387 |
+
else:
|
| 388 |
+
function = FunctionDefinition(
|
| 389 |
+
return_type = ret_type,
|
| 390 |
+
name = node.spelling,
|
| 391 |
+
parameters = param,
|
| 392 |
+
body = body
|
| 393 |
+
)
|
| 394 |
+
return function
|
| 395 |
+
|
| 396 |
+
def transform_parm_decl(self, node):
|
| 397 |
+
"""Transformation function for Parameter Declaration
|
| 398 |
+
|
| 399 |
+
Used to create parameter nodes for the required functions for the
|
| 400 |
+
respective nodes in the clang AST
|
| 401 |
+
|
| 402 |
+
Returns
|
| 403 |
+
=======
|
| 404 |
+
|
| 405 |
+
param : Codegen AST Node
|
| 406 |
+
Variable node with the value and type of the variable
|
| 407 |
+
|
| 408 |
+
Raises
|
| 409 |
+
======
|
| 410 |
+
|
| 411 |
+
ValueError if multiple children encountered in the parameter node
|
| 412 |
+
|
| 413 |
+
"""
|
| 414 |
+
if node.type.kind in self._data_types["int"]:
|
| 415 |
+
type = self._data_types["int"][node.type.kind]
|
| 416 |
+
elif node.type.kind in self._data_types["float"]:
|
| 417 |
+
type = self._data_types["float"][node.type.kind]
|
| 418 |
+
elif node.type.kind in self._data_types["bool"]:
|
| 419 |
+
type = self._data_types["bool"][node.type.kind]
|
| 420 |
+
else:
|
| 421 |
+
raise NotImplementedError("Only bool, int "
|
| 422 |
+
"and float are supported")
|
| 423 |
+
try:
|
| 424 |
+
children = node.get_children()
|
| 425 |
+
child = next(children)
|
| 426 |
+
|
| 427 |
+
# Any namespace nodes can be ignored
|
| 428 |
+
while child.kind in [cin.CursorKind.NAMESPACE_REF,
|
| 429 |
+
cin.CursorKind.TYPE_REF,
|
| 430 |
+
cin.CursorKind.TEMPLATE_REF]:
|
| 431 |
+
child = next(children)
|
| 432 |
+
|
| 433 |
+
# If there is a child, it is the default value of the parameter.
|
| 434 |
+
lit = self.transform(child)
|
| 435 |
+
if node.type.kind in self._data_types["int"]:
|
| 436 |
+
val = Integer(lit)
|
| 437 |
+
elif node.type.kind in self._data_types["float"]:
|
| 438 |
+
val = Float(lit)
|
| 439 |
+
elif node.type.kind in self._data_types["bool"]:
|
| 440 |
+
val = sympify(bool(lit))
|
| 441 |
+
else:
|
| 442 |
+
raise NotImplementedError("Only bool, int "
|
| 443 |
+
"and float are supported")
|
| 444 |
+
|
| 445 |
+
param = Variable(
|
| 446 |
+
node.spelling
|
| 447 |
+
).as_Declaration(
|
| 448 |
+
type = type,
|
| 449 |
+
value = val
|
| 450 |
+
)
|
| 451 |
+
except StopIteration:
|
| 452 |
+
param = Variable(
|
| 453 |
+
node.spelling
|
| 454 |
+
).as_Declaration(
|
| 455 |
+
type = type
|
| 456 |
+
)
|
| 457 |
+
|
| 458 |
+
try:
|
| 459 |
+
self.transform(next(children))
|
| 460 |
+
raise ValueError("Can't handle multiple children on parameter")
|
| 461 |
+
except StopIteration:
|
| 462 |
+
pass
|
| 463 |
+
|
| 464 |
+
return param
|
| 465 |
+
|
| 466 |
+
def transform_integer_literal(self, node):
|
| 467 |
+
"""Transformation function for integer literal
|
| 468 |
+
|
| 469 |
+
Used to get the value and type of the given integer literal.
|
| 470 |
+
|
| 471 |
+
Returns
|
| 472 |
+
=======
|
| 473 |
+
|
| 474 |
+
val : list
|
| 475 |
+
List with two arguments type and Value
|
| 476 |
+
type contains the type of the integer
|
| 477 |
+
value contains the value stored in the variable
|
| 478 |
+
|
| 479 |
+
Notes
|
| 480 |
+
=====
|
| 481 |
+
|
| 482 |
+
Only Base Integer type supported for now
|
| 483 |
+
|
| 484 |
+
"""
|
| 485 |
+
try:
|
| 486 |
+
value = next(node.get_tokens()).spelling
|
| 487 |
+
except StopIteration:
|
| 488 |
+
# No tokens
|
| 489 |
+
value = node.literal
|
| 490 |
+
return int(value)
|
| 491 |
+
|
| 492 |
+
def transform_floating_literal(self, node):
|
| 493 |
+
"""Transformation function for floating literal
|
| 494 |
+
|
| 495 |
+
Used to get the value and type of the given floating literal.
|
| 496 |
+
|
| 497 |
+
Returns
|
| 498 |
+
=======
|
| 499 |
+
|
| 500 |
+
val : list
|
| 501 |
+
List with two arguments type and Value
|
| 502 |
+
type contains the type of float
|
| 503 |
+
value contains the value stored in the variable
|
| 504 |
+
|
| 505 |
+
Notes
|
| 506 |
+
=====
|
| 507 |
+
|
| 508 |
+
Only Base Float type supported for now
|
| 509 |
+
|
| 510 |
+
"""
|
| 511 |
+
try:
|
| 512 |
+
value = next(node.get_tokens()).spelling
|
| 513 |
+
except (StopIteration, ValueError):
|
| 514 |
+
# No tokens
|
| 515 |
+
value = node.literal
|
| 516 |
+
return float(value)
|
| 517 |
+
|
| 518 |
+
def transform_string_literal(self, node):
|
| 519 |
+
#TODO: No string type in AST
|
| 520 |
+
#type =
|
| 521 |
+
#try:
|
| 522 |
+
# value = next(node.get_tokens()).spelling
|
| 523 |
+
#except (StopIteration, ValueError):
|
| 524 |
+
# No tokens
|
| 525 |
+
# value = node.literal
|
| 526 |
+
#val = [type, value]
|
| 527 |
+
#return val
|
| 528 |
+
pass
|
| 529 |
+
|
| 530 |
+
def transform_character_literal(self, node):
|
| 531 |
+
"""Transformation function for character literal
|
| 532 |
+
|
| 533 |
+
Used to get the value of the given character literal.
|
| 534 |
+
|
| 535 |
+
Returns
|
| 536 |
+
=======
|
| 537 |
+
|
| 538 |
+
val : int
|
| 539 |
+
val contains the ascii value of the character literal
|
| 540 |
+
|
| 541 |
+
Notes
|
| 542 |
+
=====
|
| 543 |
+
|
| 544 |
+
Only for cases where character is assigned to a integer value,
|
| 545 |
+
since character literal is not in SymPy AST
|
| 546 |
+
|
| 547 |
+
"""
|
| 548 |
+
try:
|
| 549 |
+
value = next(node.get_tokens()).spelling
|
| 550 |
+
except (StopIteration, ValueError):
|
| 551 |
+
# No tokens
|
| 552 |
+
value = node.literal
|
| 553 |
+
return ord(str(value[1]))
|
| 554 |
+
|
| 555 |
+
def transform_cxx_bool_literal_expr(self, node):
|
| 556 |
+
"""Transformation function for boolean literal
|
| 557 |
+
|
| 558 |
+
Used to get the value of the given boolean literal.
|
| 559 |
+
|
| 560 |
+
Returns
|
| 561 |
+
=======
|
| 562 |
+
|
| 563 |
+
value : bool
|
| 564 |
+
value contains the boolean value of the variable
|
| 565 |
+
|
| 566 |
+
"""
|
| 567 |
+
try:
|
| 568 |
+
value = next(node.get_tokens()).spelling
|
| 569 |
+
except (StopIteration, ValueError):
|
| 570 |
+
value = node.literal
|
| 571 |
+
return True if value == 'true' else False
|
| 572 |
+
|
| 573 |
+
def transform_unexposed_decl(self,node):
|
| 574 |
+
"""Transformation function for unexposed declarations"""
|
| 575 |
+
pass
|
| 576 |
+
|
| 577 |
+
def transform_unexposed_expr(self, node):
|
| 578 |
+
"""Transformation function for unexposed expression
|
| 579 |
+
|
| 580 |
+
Unexposed expressions are used to wrap float, double literals and
|
| 581 |
+
expressions
|
| 582 |
+
|
| 583 |
+
Returns
|
| 584 |
+
=======
|
| 585 |
+
|
| 586 |
+
expr : Codegen AST Node
|
| 587 |
+
the result from the wrapped expression
|
| 588 |
+
|
| 589 |
+
None : NoneType
|
| 590 |
+
No childs are found for the node
|
| 591 |
+
|
| 592 |
+
Raises
|
| 593 |
+
======
|
| 594 |
+
|
| 595 |
+
ValueError if the expression contains multiple children
|
| 596 |
+
|
| 597 |
+
"""
|
| 598 |
+
# Ignore unexposed nodes; pass whatever is the first
|
| 599 |
+
# (and should be only) child unaltered.
|
| 600 |
+
try:
|
| 601 |
+
children = node.get_children()
|
| 602 |
+
expr = self.transform(next(children))
|
| 603 |
+
except StopIteration:
|
| 604 |
+
return None
|
| 605 |
+
|
| 606 |
+
try:
|
| 607 |
+
next(children)
|
| 608 |
+
raise ValueError("Unexposed expression has > 1 children.")
|
| 609 |
+
except StopIteration:
|
| 610 |
+
pass
|
| 611 |
+
|
| 612 |
+
return expr
|
| 613 |
+
|
| 614 |
+
def transform_decl_ref_expr(self, node):
|
| 615 |
+
"""Returns the name of the declaration reference"""
|
| 616 |
+
return node.spelling
|
| 617 |
+
|
| 618 |
+
def transform_call_expr(self, node):
|
| 619 |
+
"""Transformation function for a call expression
|
| 620 |
+
|
| 621 |
+
Used to create function call nodes for the function calls present
|
| 622 |
+
in the C code
|
| 623 |
+
|
| 624 |
+
Returns
|
| 625 |
+
=======
|
| 626 |
+
|
| 627 |
+
FunctionCall : Codegen AST Node
|
| 628 |
+
FunctionCall node with parameters if any parameters are present
|
| 629 |
+
|
| 630 |
+
"""
|
| 631 |
+
param = []
|
| 632 |
+
children = node.get_children()
|
| 633 |
+
child = next(children)
|
| 634 |
+
|
| 635 |
+
while child.kind == cin.CursorKind.NAMESPACE_REF:
|
| 636 |
+
child = next(children)
|
| 637 |
+
while child.kind == cin.CursorKind.TYPE_REF:
|
| 638 |
+
child = next(children)
|
| 639 |
+
|
| 640 |
+
first_child = self.transform(child)
|
| 641 |
+
try:
|
| 642 |
+
for child in children:
|
| 643 |
+
arg = self.transform(child)
|
| 644 |
+
if child.kind == cin.CursorKind.INTEGER_LITERAL:
|
| 645 |
+
param.append(Integer(arg))
|
| 646 |
+
elif child.kind == cin.CursorKind.FLOATING_LITERAL:
|
| 647 |
+
param.append(Float(arg))
|
| 648 |
+
else:
|
| 649 |
+
param.append(arg)
|
| 650 |
+
return FunctionCall(first_child, param)
|
| 651 |
+
|
| 652 |
+
except StopIteration:
|
| 653 |
+
return FunctionCall(first_child)
|
| 654 |
+
|
| 655 |
+
def transform_return_stmt(self, node):
|
| 656 |
+
"""Returns the Return Node for a return statement"""
|
| 657 |
+
return Return(next(node.get_children()).spelling)
|
| 658 |
+
|
| 659 |
+
def transform_compound_stmt(self, node):
|
| 660 |
+
"""Transformation function for compond statemets
|
| 661 |
+
|
| 662 |
+
Returns
|
| 663 |
+
=======
|
| 664 |
+
|
| 665 |
+
expr : list
|
| 666 |
+
list of Nodes for the expressions present in the statement
|
| 667 |
+
|
| 668 |
+
None : NoneType
|
| 669 |
+
if the compound statement is empty
|
| 670 |
+
|
| 671 |
+
"""
|
| 672 |
+
expr = []
|
| 673 |
+
children = node.get_children()
|
| 674 |
+
|
| 675 |
+
for child in children:
|
| 676 |
+
expr.append(self.transform(child))
|
| 677 |
+
return expr
|
| 678 |
+
|
| 679 |
+
def transform_decl_stmt(self, node):
|
| 680 |
+
"""Transformation function for declaration statements
|
| 681 |
+
|
| 682 |
+
These statements are used to wrap different kinds of declararions
|
| 683 |
+
like variable or function declaration
|
| 684 |
+
The function calls the transformer function for the child of the
|
| 685 |
+
given node
|
| 686 |
+
|
| 687 |
+
Returns
|
| 688 |
+
=======
|
| 689 |
+
|
| 690 |
+
statement : Codegen AST Node
|
| 691 |
+
contains the node returned by the children node for the type of
|
| 692 |
+
declaration
|
| 693 |
+
|
| 694 |
+
Raises
|
| 695 |
+
======
|
| 696 |
+
|
| 697 |
+
ValueError if multiple children present
|
| 698 |
+
|
| 699 |
+
"""
|
| 700 |
+
try:
|
| 701 |
+
children = node.get_children()
|
| 702 |
+
statement = self.transform(next(children))
|
| 703 |
+
except StopIteration:
|
| 704 |
+
pass
|
| 705 |
+
|
| 706 |
+
try:
|
| 707 |
+
self.transform(next(children))
|
| 708 |
+
raise ValueError("Don't know how to handle multiple statements")
|
| 709 |
+
except StopIteration:
|
| 710 |
+
pass
|
| 711 |
+
|
| 712 |
+
return statement
|
| 713 |
+
|
| 714 |
+
def transform_paren_expr(self, node):
|
| 715 |
+
"""Transformation function for Parenthesized expressions
|
| 716 |
+
|
| 717 |
+
Returns the result from its children nodes
|
| 718 |
+
|
| 719 |
+
"""
|
| 720 |
+
return self.transform(next(node.get_children()))
|
| 721 |
+
|
| 722 |
+
def transform_compound_assignment_operator(self, node):
|
| 723 |
+
"""Transformation function for handling shorthand operators
|
| 724 |
+
|
| 725 |
+
Returns
|
| 726 |
+
=======
|
| 727 |
+
|
| 728 |
+
augmented_assignment_expression: Codegen AST node
|
| 729 |
+
shorthand assignment expression represented as Codegen AST
|
| 730 |
+
|
| 731 |
+
Raises
|
| 732 |
+
======
|
| 733 |
+
|
| 734 |
+
NotImplementedError
|
| 735 |
+
If the shorthand operator for bitwise operators
|
| 736 |
+
(~=, ^=, &=, |=, <<=, >>=) is encountered
|
| 737 |
+
|
| 738 |
+
"""
|
| 739 |
+
return self.transform_binary_operator(node)
|
| 740 |
+
|
| 741 |
+
def transform_unary_operator(self, node):
|
| 742 |
+
"""Transformation function for handling unary operators
|
| 743 |
+
|
| 744 |
+
Returns
|
| 745 |
+
=======
|
| 746 |
+
|
| 747 |
+
unary_expression: Codegen AST node
|
| 748 |
+
simplified unary expression represented as Codegen AST
|
| 749 |
+
|
| 750 |
+
Raises
|
| 751 |
+
======
|
| 752 |
+
|
| 753 |
+
NotImplementedError
|
| 754 |
+
If dereferencing operator(*), address operator(&) or
|
| 755 |
+
bitwise NOT operator(~) is encountered
|
| 756 |
+
|
| 757 |
+
"""
|
| 758 |
+
# supported operators list
|
| 759 |
+
operators_list = ['+', '-', '++', '--', '!']
|
| 760 |
+
tokens = list(node.get_tokens())
|
| 761 |
+
|
| 762 |
+
# it can be either pre increment/decrement or any other operator from the list
|
| 763 |
+
if tokens[0].spelling in operators_list:
|
| 764 |
+
child = self.transform(next(node.get_children()))
|
| 765 |
+
# (decl_ref) e.g.; int a = ++b; or simply ++b;
|
| 766 |
+
if isinstance(child, str):
|
| 767 |
+
if tokens[0].spelling == '+':
|
| 768 |
+
return Symbol(child)
|
| 769 |
+
if tokens[0].spelling == '-':
|
| 770 |
+
return Mul(Symbol(child), -1)
|
| 771 |
+
if tokens[0].spelling == '++':
|
| 772 |
+
return PreIncrement(Symbol(child))
|
| 773 |
+
if tokens[0].spelling == '--':
|
| 774 |
+
return PreDecrement(Symbol(child))
|
| 775 |
+
if tokens[0].spelling == '!':
|
| 776 |
+
return Not(Symbol(child))
|
| 777 |
+
# e.g.; int a = -1; or int b = -(1 + 2);
|
| 778 |
+
else:
|
| 779 |
+
if tokens[0].spelling == '+':
|
| 780 |
+
return child
|
| 781 |
+
if tokens[0].spelling == '-':
|
| 782 |
+
return Mul(child, -1)
|
| 783 |
+
if tokens[0].spelling == '!':
|
| 784 |
+
return Not(sympify(bool(child)))
|
| 785 |
+
|
| 786 |
+
# it can be either post increment/decrement
|
| 787 |
+
# since variable name is obtained in token[0].spelling
|
| 788 |
+
elif tokens[1].spelling in ['++', '--']:
|
| 789 |
+
child = self.transform(next(node.get_children()))
|
| 790 |
+
if tokens[1].spelling == '++':
|
| 791 |
+
return PostIncrement(Symbol(child))
|
| 792 |
+
if tokens[1].spelling == '--':
|
| 793 |
+
return PostDecrement(Symbol(child))
|
| 794 |
+
else:
|
| 795 |
+
raise NotImplementedError("Dereferencing operator, "
|
| 796 |
+
"Address operator and bitwise NOT operator "
|
| 797 |
+
"have not been implemented yet!")
|
| 798 |
+
|
| 799 |
+
def transform_binary_operator(self, node):
|
| 800 |
+
"""Transformation function for handling binary operators
|
| 801 |
+
|
| 802 |
+
Returns
|
| 803 |
+
=======
|
| 804 |
+
|
| 805 |
+
binary_expression: Codegen AST node
|
| 806 |
+
simplified binary expression represented as Codegen AST
|
| 807 |
+
|
| 808 |
+
Raises
|
| 809 |
+
======
|
| 810 |
+
|
| 811 |
+
NotImplementedError
|
| 812 |
+
If a bitwise operator or
|
| 813 |
+
unary operator(which is a child of any binary
|
| 814 |
+
operator in Clang AST) is encountered
|
| 815 |
+
|
| 816 |
+
"""
|
| 817 |
+
# get all the tokens of assignment
|
| 818 |
+
# and store it in the tokens list
|
| 819 |
+
tokens = list(node.get_tokens())
|
| 820 |
+
|
| 821 |
+
# supported operators list
|
| 822 |
+
operators_list = ['+', '-', '*', '/', '%','=',
|
| 823 |
+
'>', '>=', '<', '<=', '==', '!=', '&&', '||', '+=', '-=',
|
| 824 |
+
'*=', '/=', '%=']
|
| 825 |
+
|
| 826 |
+
# this stack will contain variable content
|
| 827 |
+
# and type of variable in the rhs
|
| 828 |
+
combined_variables_stack = []
|
| 829 |
+
|
| 830 |
+
# this stack will contain operators
|
| 831 |
+
# to be processed in the rhs
|
| 832 |
+
operators_stack = []
|
| 833 |
+
|
| 834 |
+
# iterate through every token
|
| 835 |
+
for token in tokens:
|
| 836 |
+
# token is either '(', ')' or
|
| 837 |
+
# any of the supported operators from the operator list
|
| 838 |
+
if token.kind == cin.TokenKind.PUNCTUATION:
|
| 839 |
+
|
| 840 |
+
# push '(' to the operators stack
|
| 841 |
+
if token.spelling == '(':
|
| 842 |
+
operators_stack.append('(')
|
| 843 |
+
|
| 844 |
+
elif token.spelling == ')':
|
| 845 |
+
# keep adding the expression to the
|
| 846 |
+
# combined variables stack unless
|
| 847 |
+
# '(' is found
|
| 848 |
+
while (operators_stack
|
| 849 |
+
and operators_stack[-1] != '('):
|
| 850 |
+
if len(combined_variables_stack) < 2:
|
| 851 |
+
raise NotImplementedError(
|
| 852 |
+
"Unary operators as a part of "
|
| 853 |
+
"binary operators is not "
|
| 854 |
+
"supported yet!")
|
| 855 |
+
rhs = combined_variables_stack.pop()
|
| 856 |
+
lhs = combined_variables_stack.pop()
|
| 857 |
+
operator = operators_stack.pop()
|
| 858 |
+
combined_variables_stack.append(
|
| 859 |
+
self.perform_operation(
|
| 860 |
+
lhs, rhs, operator))
|
| 861 |
+
|
| 862 |
+
# pop '('
|
| 863 |
+
operators_stack.pop()
|
| 864 |
+
|
| 865 |
+
# token is an operator (supported)
|
| 866 |
+
elif token.spelling in operators_list:
|
| 867 |
+
while (operators_stack
|
| 868 |
+
and self.priority_of(token.spelling)
|
| 869 |
+
<= self.priority_of(
|
| 870 |
+
operators_stack[-1])):
|
| 871 |
+
if len(combined_variables_stack) < 2:
|
| 872 |
+
raise NotImplementedError(
|
| 873 |
+
"Unary operators as a part of "
|
| 874 |
+
"binary operators is not "
|
| 875 |
+
"supported yet!")
|
| 876 |
+
rhs = combined_variables_stack.pop()
|
| 877 |
+
lhs = combined_variables_stack.pop()
|
| 878 |
+
operator = operators_stack.pop()
|
| 879 |
+
combined_variables_stack.append(
|
| 880 |
+
self.perform_operation(
|
| 881 |
+
lhs, rhs, operator))
|
| 882 |
+
|
| 883 |
+
# push current operator
|
| 884 |
+
operators_stack.append(token.spelling)
|
| 885 |
+
|
| 886 |
+
# token is a bitwise operator
|
| 887 |
+
elif token.spelling in ['&', '|', '^', '<<', '>>']:
|
| 888 |
+
raise NotImplementedError(
|
| 889 |
+
"Bitwise operator has not been "
|
| 890 |
+
"implemented yet!")
|
| 891 |
+
|
| 892 |
+
# token is a shorthand bitwise operator
|
| 893 |
+
elif token.spelling in ['&=', '|=', '^=', '<<=',
|
| 894 |
+
'>>=']:
|
| 895 |
+
raise NotImplementedError(
|
| 896 |
+
"Shorthand bitwise operator has not been "
|
| 897 |
+
"implemented yet!")
|
| 898 |
+
else:
|
| 899 |
+
raise NotImplementedError(
|
| 900 |
+
"Given token {} is not implemented yet!"
|
| 901 |
+
.format(token.spelling))
|
| 902 |
+
|
| 903 |
+
# token is an identifier(variable)
|
| 904 |
+
elif token.kind == cin.TokenKind.IDENTIFIER:
|
| 905 |
+
combined_variables_stack.append(
|
| 906 |
+
[token.spelling, 'identifier'])
|
| 907 |
+
|
| 908 |
+
# token is a literal
|
| 909 |
+
elif token.kind == cin.TokenKind.LITERAL:
|
| 910 |
+
combined_variables_stack.append(
|
| 911 |
+
[token.spelling, 'literal'])
|
| 912 |
+
|
| 913 |
+
# token is a keyword, either true or false
|
| 914 |
+
elif (token.kind == cin.TokenKind.KEYWORD
|
| 915 |
+
and token.spelling in ['true', 'false']):
|
| 916 |
+
combined_variables_stack.append(
|
| 917 |
+
[token.spelling, 'boolean'])
|
| 918 |
+
else:
|
| 919 |
+
raise NotImplementedError(
|
| 920 |
+
"Given token {} is not implemented yet!"
|
| 921 |
+
.format(token.spelling))
|
| 922 |
+
|
| 923 |
+
# process remaining operators
|
| 924 |
+
while operators_stack:
|
| 925 |
+
if len(combined_variables_stack) < 2:
|
| 926 |
+
raise NotImplementedError(
|
| 927 |
+
"Unary operators as a part of "
|
| 928 |
+
"binary operators is not "
|
| 929 |
+
"supported yet!")
|
| 930 |
+
rhs = combined_variables_stack.pop()
|
| 931 |
+
lhs = combined_variables_stack.pop()
|
| 932 |
+
operator = operators_stack.pop()
|
| 933 |
+
combined_variables_stack.append(
|
| 934 |
+
self.perform_operation(lhs, rhs, operator))
|
| 935 |
+
|
| 936 |
+
return combined_variables_stack[-1][0]
|
| 937 |
+
|
| 938 |
+
def priority_of(self, op):
|
| 939 |
+
"""To get the priority of given operator"""
|
| 940 |
+
if op in ['=', '+=', '-=', '*=', '/=', '%=']:
|
| 941 |
+
return 1
|
| 942 |
+
if op in ['&&', '||']:
|
| 943 |
+
return 2
|
| 944 |
+
if op in ['<', '<=', '>', '>=', '==', '!=']:
|
| 945 |
+
return 3
|
| 946 |
+
if op in ['+', '-']:
|
| 947 |
+
return 4
|
| 948 |
+
if op in ['*', '/', '%']:
|
| 949 |
+
return 5
|
| 950 |
+
return 0
|
| 951 |
+
|
| 952 |
+
def perform_operation(self, lhs, rhs, op):
|
| 953 |
+
"""Performs operation supported by the SymPy core
|
| 954 |
+
|
| 955 |
+
Returns
|
| 956 |
+
=======
|
| 957 |
+
|
| 958 |
+
combined_variable: list
|
| 959 |
+
contains variable content and type of variable
|
| 960 |
+
|
| 961 |
+
"""
|
| 962 |
+
lhs_value = self.get_expr_for_operand(lhs)
|
| 963 |
+
rhs_value = self.get_expr_for_operand(rhs)
|
| 964 |
+
if op == '+':
|
| 965 |
+
return [Add(lhs_value, rhs_value), 'expr']
|
| 966 |
+
if op == '-':
|
| 967 |
+
return [Add(lhs_value, -rhs_value), 'expr']
|
| 968 |
+
if op == '*':
|
| 969 |
+
return [Mul(lhs_value, rhs_value), 'expr']
|
| 970 |
+
if op == '/':
|
| 971 |
+
return [Mul(lhs_value, Pow(rhs_value, Integer(-1))), 'expr']
|
| 972 |
+
if op == '%':
|
| 973 |
+
return [Mod(lhs_value, rhs_value), 'expr']
|
| 974 |
+
if op in ['<', '<=', '>', '>=', '==', '!=']:
|
| 975 |
+
return [Rel(lhs_value, rhs_value, op), 'expr']
|
| 976 |
+
if op == '&&':
|
| 977 |
+
return [And(as_Boolean(lhs_value), as_Boolean(rhs_value)), 'expr']
|
| 978 |
+
if op == '||':
|
| 979 |
+
return [Or(as_Boolean(lhs_value), as_Boolean(rhs_value)), 'expr']
|
| 980 |
+
if op == '=':
|
| 981 |
+
return [Assignment(Variable(lhs_value), rhs_value), 'expr']
|
| 982 |
+
if op in ['+=', '-=', '*=', '/=', '%=']:
|
| 983 |
+
return [aug_assign(Variable(lhs_value), op[0], rhs_value), 'expr']
|
| 984 |
+
|
| 985 |
+
def get_expr_for_operand(self, combined_variable):
|
| 986 |
+
"""Gives out SymPy Codegen AST node
|
| 987 |
+
|
| 988 |
+
AST node returned is corresponding to
|
| 989 |
+
combined variable passed.Combined variable contains
|
| 990 |
+
variable content and type of variable
|
| 991 |
+
|
| 992 |
+
"""
|
| 993 |
+
if combined_variable[1] == 'identifier':
|
| 994 |
+
return Symbol(combined_variable[0])
|
| 995 |
+
if combined_variable[1] == 'literal':
|
| 996 |
+
if '.' in combined_variable[0]:
|
| 997 |
+
return Float(float(combined_variable[0]))
|
| 998 |
+
else:
|
| 999 |
+
return Integer(int(combined_variable[0]))
|
| 1000 |
+
if combined_variable[1] == 'expr':
|
| 1001 |
+
return combined_variable[0]
|
| 1002 |
+
if combined_variable[1] == 'boolean':
|
| 1003 |
+
return true if combined_variable[0] == 'true' else false
|
| 1004 |
+
|
| 1005 |
+
def transform_null_stmt(self, node):
|
| 1006 |
+
"""Handles Null Statement and returns None"""
|
| 1007 |
+
return none
|
| 1008 |
+
|
| 1009 |
+
def transform_while_stmt(self, node):
|
| 1010 |
+
"""Transformation function for handling while statement
|
| 1011 |
+
|
| 1012 |
+
Returns
|
| 1013 |
+
=======
|
| 1014 |
+
|
| 1015 |
+
while statement : Codegen AST Node
|
| 1016 |
+
contains the while statement node having condition and
|
| 1017 |
+
statement block
|
| 1018 |
+
|
| 1019 |
+
"""
|
| 1020 |
+
children = node.get_children()
|
| 1021 |
+
|
| 1022 |
+
condition = self.transform(next(children))
|
| 1023 |
+
statements = self.transform(next(children))
|
| 1024 |
+
|
| 1025 |
+
if isinstance(statements, list):
|
| 1026 |
+
statement_block = CodeBlock(*statements)
|
| 1027 |
+
else:
|
| 1028 |
+
statement_block = CodeBlock(statements)
|
| 1029 |
+
|
| 1030 |
+
return While(condition, statement_block)
|
| 1031 |
+
|
| 1032 |
+
|
| 1033 |
+
|
| 1034 |
+
else:
|
| 1035 |
+
class CCodeConverter(): # type: ignore
|
| 1036 |
+
def __init__(self, *args, **kwargs):
|
| 1037 |
+
raise ImportError("Module not Installed")
|
| 1038 |
+
|
| 1039 |
+
|
| 1040 |
+
def parse_c(source):
|
| 1041 |
+
"""Function for converting a C source code
|
| 1042 |
+
|
| 1043 |
+
The function reads the source code present in the given file and parses it
|
| 1044 |
+
to give out SymPy Expressions
|
| 1045 |
+
|
| 1046 |
+
Returns
|
| 1047 |
+
=======
|
| 1048 |
+
|
| 1049 |
+
src : list
|
| 1050 |
+
List of Python expression strings
|
| 1051 |
+
|
| 1052 |
+
"""
|
| 1053 |
+
converter = CCodeConverter()
|
| 1054 |
+
if os.path.exists(source):
|
| 1055 |
+
src = converter.parse(source, flags = [])
|
| 1056 |
+
else:
|
| 1057 |
+
src = converter.parse_str(source, flags = [])
|
| 1058 |
+
return src
|
lib/python3.12/site-packages/sympy/parsing/latex/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The MIT License (MIT)
|
| 2 |
+
|
| 3 |
+
Copyright 2016, latex2sympy
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
lib/python3.12/site-packages/sympy/parsing/latex/LaTeX.g4
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
ANTLR4 LaTeX Math Grammar
|
| 3 |
+
|
| 4 |
+
Ported from latex2sympy by @augustt198 https://github.com/augustt198/latex2sympy See license in
|
| 5 |
+
LICENSE.txt
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
/*
|
| 9 |
+
After changing this file, it is necessary to run `python setup.py antlr` in the root directory of
|
| 10 |
+
the repository. This will regenerate the code in `sympy/parsing/latex/_antlr/*.py`.
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
grammar LaTeX;
|
| 14 |
+
|
| 15 |
+
options {
|
| 16 |
+
language = Python3;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
WS: [ \t\r\n]+ -> skip;
|
| 20 |
+
THINSPACE: ('\\,' | '\\thinspace') -> skip;
|
| 21 |
+
MEDSPACE: ('\\:' | '\\medspace') -> skip;
|
| 22 |
+
THICKSPACE: ('\\;' | '\\thickspace') -> skip;
|
| 23 |
+
QUAD: '\\quad' -> skip;
|
| 24 |
+
QQUAD: '\\qquad' -> skip;
|
| 25 |
+
NEGTHINSPACE: ('\\!' | '\\negthinspace') -> skip;
|
| 26 |
+
NEGMEDSPACE: '\\negmedspace' -> skip;
|
| 27 |
+
NEGTHICKSPACE: '\\negthickspace' -> skip;
|
| 28 |
+
CMD_LEFT: '\\left' -> skip;
|
| 29 |
+
CMD_RIGHT: '\\right' -> skip;
|
| 30 |
+
|
| 31 |
+
IGNORE:
|
| 32 |
+
(
|
| 33 |
+
'\\vrule'
|
| 34 |
+
| '\\vcenter'
|
| 35 |
+
| '\\vbox'
|
| 36 |
+
| '\\vskip'
|
| 37 |
+
| '\\vspace'
|
| 38 |
+
| '\\hfil'
|
| 39 |
+
| '\\*'
|
| 40 |
+
| '\\-'
|
| 41 |
+
| '\\.'
|
| 42 |
+
| '\\/'
|
| 43 |
+
| '\\"'
|
| 44 |
+
| '\\('
|
| 45 |
+
| '\\='
|
| 46 |
+
) -> skip;
|
| 47 |
+
|
| 48 |
+
ADD: '+';
|
| 49 |
+
SUB: '-';
|
| 50 |
+
MUL: '*';
|
| 51 |
+
DIV: '/';
|
| 52 |
+
|
| 53 |
+
L_PAREN: '(';
|
| 54 |
+
R_PAREN: ')';
|
| 55 |
+
L_BRACE: '{';
|
| 56 |
+
R_BRACE: '}';
|
| 57 |
+
L_BRACE_LITERAL: '\\{';
|
| 58 |
+
R_BRACE_LITERAL: '\\}';
|
| 59 |
+
L_BRACKET: '[';
|
| 60 |
+
R_BRACKET: ']';
|
| 61 |
+
|
| 62 |
+
BAR: '|';
|
| 63 |
+
|
| 64 |
+
R_BAR: '\\right|';
|
| 65 |
+
L_BAR: '\\left|';
|
| 66 |
+
|
| 67 |
+
L_ANGLE: '\\langle';
|
| 68 |
+
R_ANGLE: '\\rangle';
|
| 69 |
+
FUNC_LIM: '\\lim';
|
| 70 |
+
LIM_APPROACH_SYM:
|
| 71 |
+
'\\to'
|
| 72 |
+
| '\\rightarrow'
|
| 73 |
+
| '\\Rightarrow'
|
| 74 |
+
| '\\longrightarrow'
|
| 75 |
+
| '\\Longrightarrow';
|
| 76 |
+
FUNC_INT:
|
| 77 |
+
'\\int'
|
| 78 |
+
| '\\int\\limits';
|
| 79 |
+
FUNC_SUM: '\\sum';
|
| 80 |
+
FUNC_PROD: '\\prod';
|
| 81 |
+
|
| 82 |
+
FUNC_EXP: '\\exp';
|
| 83 |
+
FUNC_LOG: '\\log';
|
| 84 |
+
FUNC_LG: '\\lg';
|
| 85 |
+
FUNC_LN: '\\ln';
|
| 86 |
+
FUNC_SIN: '\\sin';
|
| 87 |
+
FUNC_COS: '\\cos';
|
| 88 |
+
FUNC_TAN: '\\tan';
|
| 89 |
+
FUNC_CSC: '\\csc';
|
| 90 |
+
FUNC_SEC: '\\sec';
|
| 91 |
+
FUNC_COT: '\\cot';
|
| 92 |
+
|
| 93 |
+
FUNC_ARCSIN: '\\arcsin';
|
| 94 |
+
FUNC_ARCCOS: '\\arccos';
|
| 95 |
+
FUNC_ARCTAN: '\\arctan';
|
| 96 |
+
FUNC_ARCCSC: '\\arccsc';
|
| 97 |
+
FUNC_ARCSEC: '\\arcsec';
|
| 98 |
+
FUNC_ARCCOT: '\\arccot';
|
| 99 |
+
|
| 100 |
+
FUNC_SINH: '\\sinh';
|
| 101 |
+
FUNC_COSH: '\\cosh';
|
| 102 |
+
FUNC_TANH: '\\tanh';
|
| 103 |
+
FUNC_ARSINH: '\\arsinh';
|
| 104 |
+
FUNC_ARCOSH: '\\arcosh';
|
| 105 |
+
FUNC_ARTANH: '\\artanh';
|
| 106 |
+
|
| 107 |
+
L_FLOOR: '\\lfloor';
|
| 108 |
+
R_FLOOR: '\\rfloor';
|
| 109 |
+
L_CEIL: '\\lceil';
|
| 110 |
+
R_CEIL: '\\rceil';
|
| 111 |
+
|
| 112 |
+
FUNC_SQRT: '\\sqrt';
|
| 113 |
+
FUNC_OVERLINE: '\\overline';
|
| 114 |
+
|
| 115 |
+
CMD_TIMES: '\\times';
|
| 116 |
+
CMD_CDOT: '\\cdot';
|
| 117 |
+
CMD_DIV: '\\div';
|
| 118 |
+
CMD_FRAC:
|
| 119 |
+
'\\frac'
|
| 120 |
+
| '\\dfrac'
|
| 121 |
+
| '\\tfrac';
|
| 122 |
+
CMD_BINOM: '\\binom';
|
| 123 |
+
CMD_DBINOM: '\\dbinom';
|
| 124 |
+
CMD_TBINOM: '\\tbinom';
|
| 125 |
+
|
| 126 |
+
CMD_MATHIT: '\\mathit';
|
| 127 |
+
|
| 128 |
+
UNDERSCORE: '_';
|
| 129 |
+
CARET: '^';
|
| 130 |
+
COLON: ':';
|
| 131 |
+
|
| 132 |
+
fragment WS_CHAR: [ \t\r\n];
|
| 133 |
+
DIFFERENTIAL: 'd' WS_CHAR*? ([a-zA-Z] | '\\' [a-zA-Z]+);
|
| 134 |
+
|
| 135 |
+
LETTER: [a-zA-Z];
|
| 136 |
+
DIGIT: [0-9];
|
| 137 |
+
|
| 138 |
+
EQUAL: (('&' WS_CHAR*?)? '=') | ('=' (WS_CHAR*? '&')?);
|
| 139 |
+
NEQ: '\\neq';
|
| 140 |
+
|
| 141 |
+
LT: '<';
|
| 142 |
+
LTE: ('\\leq' | '\\le' | LTE_Q | LTE_S);
|
| 143 |
+
LTE_Q: '\\leqq';
|
| 144 |
+
LTE_S: '\\leqslant';
|
| 145 |
+
|
| 146 |
+
GT: '>';
|
| 147 |
+
GTE: ('\\geq' | '\\ge' | GTE_Q | GTE_S);
|
| 148 |
+
GTE_Q: '\\geqq';
|
| 149 |
+
GTE_S: '\\geqslant';
|
| 150 |
+
|
| 151 |
+
BANG: '!';
|
| 152 |
+
|
| 153 |
+
SINGLE_QUOTES: '\''+;
|
| 154 |
+
|
| 155 |
+
SYMBOL: '\\' [a-zA-Z]+;
|
| 156 |
+
|
| 157 |
+
math: relation;
|
| 158 |
+
|
| 159 |
+
relation:
|
| 160 |
+
relation (EQUAL | LT | LTE | GT | GTE | NEQ) relation
|
| 161 |
+
| expr;
|
| 162 |
+
|
| 163 |
+
equality: expr EQUAL expr;
|
| 164 |
+
|
| 165 |
+
expr: additive;
|
| 166 |
+
|
| 167 |
+
additive: additive (ADD | SUB) additive | mp;
|
| 168 |
+
|
| 169 |
+
// mult part
|
| 170 |
+
mp:
|
| 171 |
+
mp (MUL | CMD_TIMES | CMD_CDOT | DIV | CMD_DIV | COLON) mp
|
| 172 |
+
| unary;
|
| 173 |
+
|
| 174 |
+
mp_nofunc:
|
| 175 |
+
mp_nofunc (
|
| 176 |
+
MUL
|
| 177 |
+
| CMD_TIMES
|
| 178 |
+
| CMD_CDOT
|
| 179 |
+
| DIV
|
| 180 |
+
| CMD_DIV
|
| 181 |
+
| COLON
|
| 182 |
+
) mp_nofunc
|
| 183 |
+
| unary_nofunc;
|
| 184 |
+
|
| 185 |
+
unary: (ADD | SUB) unary | postfix+;
|
| 186 |
+
|
| 187 |
+
unary_nofunc:
|
| 188 |
+
(ADD | SUB) unary_nofunc
|
| 189 |
+
| postfix postfix_nofunc*;
|
| 190 |
+
|
| 191 |
+
postfix: exp postfix_op*;
|
| 192 |
+
postfix_nofunc: exp_nofunc postfix_op*;
|
| 193 |
+
postfix_op: BANG | eval_at;
|
| 194 |
+
|
| 195 |
+
eval_at:
|
| 196 |
+
BAR (eval_at_sup | eval_at_sub | eval_at_sup eval_at_sub);
|
| 197 |
+
|
| 198 |
+
eval_at_sub: UNDERSCORE L_BRACE (expr | equality) R_BRACE;
|
| 199 |
+
|
| 200 |
+
eval_at_sup: CARET L_BRACE (expr | equality) R_BRACE;
|
| 201 |
+
|
| 202 |
+
exp: exp CARET (atom | L_BRACE expr R_BRACE) subexpr? | comp;
|
| 203 |
+
|
| 204 |
+
exp_nofunc:
|
| 205 |
+
exp_nofunc CARET (atom | L_BRACE expr R_BRACE) subexpr?
|
| 206 |
+
| comp_nofunc;
|
| 207 |
+
|
| 208 |
+
comp:
|
| 209 |
+
group
|
| 210 |
+
| abs_group
|
| 211 |
+
| func
|
| 212 |
+
| atom
|
| 213 |
+
| floor
|
| 214 |
+
| ceil;
|
| 215 |
+
|
| 216 |
+
comp_nofunc:
|
| 217 |
+
group
|
| 218 |
+
| abs_group
|
| 219 |
+
| atom
|
| 220 |
+
| floor
|
| 221 |
+
| ceil;
|
| 222 |
+
|
| 223 |
+
group:
|
| 224 |
+
L_PAREN expr R_PAREN
|
| 225 |
+
| L_BRACKET expr R_BRACKET
|
| 226 |
+
| L_BRACE expr R_BRACE
|
| 227 |
+
| L_BRACE_LITERAL expr R_BRACE_LITERAL;
|
| 228 |
+
|
| 229 |
+
abs_group: BAR expr BAR;
|
| 230 |
+
|
| 231 |
+
number: DIGIT+ (',' DIGIT DIGIT DIGIT)* ('.' DIGIT+)?;
|
| 232 |
+
|
| 233 |
+
atom: (LETTER | SYMBOL) (subexpr? SINGLE_QUOTES? | SINGLE_QUOTES? subexpr?)
|
| 234 |
+
| number
|
| 235 |
+
| DIFFERENTIAL
|
| 236 |
+
| mathit
|
| 237 |
+
| frac
|
| 238 |
+
| binom
|
| 239 |
+
| bra
|
| 240 |
+
| ket;
|
| 241 |
+
|
| 242 |
+
bra: L_ANGLE expr (R_BAR | BAR);
|
| 243 |
+
ket: (L_BAR | BAR) expr R_ANGLE;
|
| 244 |
+
|
| 245 |
+
mathit: CMD_MATHIT L_BRACE mathit_text R_BRACE;
|
| 246 |
+
mathit_text: LETTER*;
|
| 247 |
+
|
| 248 |
+
frac: CMD_FRAC (upperd = DIGIT | L_BRACE upper = expr R_BRACE)
|
| 249 |
+
(lowerd = DIGIT | L_BRACE lower = expr R_BRACE);
|
| 250 |
+
|
| 251 |
+
binom:
|
| 252 |
+
(CMD_BINOM | CMD_DBINOM | CMD_TBINOM) L_BRACE n = expr R_BRACE L_BRACE k = expr R_BRACE;
|
| 253 |
+
|
| 254 |
+
floor: L_FLOOR val = expr R_FLOOR;
|
| 255 |
+
ceil: L_CEIL val = expr R_CEIL;
|
| 256 |
+
|
| 257 |
+
func_normal:
|
| 258 |
+
FUNC_EXP
|
| 259 |
+
| FUNC_LOG
|
| 260 |
+
| FUNC_LG
|
| 261 |
+
| FUNC_LN
|
| 262 |
+
| FUNC_SIN
|
| 263 |
+
| FUNC_COS
|
| 264 |
+
| FUNC_TAN
|
| 265 |
+
| FUNC_CSC
|
| 266 |
+
| FUNC_SEC
|
| 267 |
+
| FUNC_COT
|
| 268 |
+
| FUNC_ARCSIN
|
| 269 |
+
| FUNC_ARCCOS
|
| 270 |
+
| FUNC_ARCTAN
|
| 271 |
+
| FUNC_ARCCSC
|
| 272 |
+
| FUNC_ARCSEC
|
| 273 |
+
| FUNC_ARCCOT
|
| 274 |
+
| FUNC_SINH
|
| 275 |
+
| FUNC_COSH
|
| 276 |
+
| FUNC_TANH
|
| 277 |
+
| FUNC_ARSINH
|
| 278 |
+
| FUNC_ARCOSH
|
| 279 |
+
| FUNC_ARTANH;
|
| 280 |
+
|
| 281 |
+
func:
|
| 282 |
+
func_normal (subexpr? supexpr? | supexpr? subexpr?) (
|
| 283 |
+
L_PAREN func_arg R_PAREN
|
| 284 |
+
| func_arg_noparens
|
| 285 |
+
)
|
| 286 |
+
| (LETTER | SYMBOL) (subexpr? SINGLE_QUOTES? | SINGLE_QUOTES? subexpr?) // e.g. f(x), f_1'(x)
|
| 287 |
+
L_PAREN args R_PAREN
|
| 288 |
+
| FUNC_INT (subexpr supexpr | supexpr subexpr)? (
|
| 289 |
+
additive? DIFFERENTIAL
|
| 290 |
+
| frac
|
| 291 |
+
| additive
|
| 292 |
+
)
|
| 293 |
+
| FUNC_SQRT (L_BRACKET root = expr R_BRACKET)? L_BRACE base = expr R_BRACE
|
| 294 |
+
| FUNC_OVERLINE L_BRACE base = expr R_BRACE
|
| 295 |
+
| (FUNC_SUM | FUNC_PROD) (subeq supexpr | supexpr subeq) mp
|
| 296 |
+
| FUNC_LIM limit_sub mp;
|
| 297 |
+
|
| 298 |
+
args: (expr ',' args) | expr;
|
| 299 |
+
|
| 300 |
+
limit_sub:
|
| 301 |
+
UNDERSCORE L_BRACE (LETTER | SYMBOL) LIM_APPROACH_SYM expr (
|
| 302 |
+
CARET ((L_BRACE (ADD | SUB) R_BRACE) | ADD | SUB)
|
| 303 |
+
)? R_BRACE;
|
| 304 |
+
|
| 305 |
+
func_arg: expr | (expr ',' func_arg);
|
| 306 |
+
func_arg_noparens: mp_nofunc;
|
| 307 |
+
|
| 308 |
+
subexpr: UNDERSCORE (atom | L_BRACE expr R_BRACE);
|
| 309 |
+
supexpr: CARET (atom | L_BRACE expr R_BRACE);
|
| 310 |
+
|
| 311 |
+
subeq: UNDERSCORE L_BRACE equality R_BRACE;
|
| 312 |
+
supeq: UNDERSCORE L_BRACE equality R_BRACE;
|
lib/python3.12/site-packages/sympy/parsing/latex/__init__.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.external import import_module
|
| 2 |
+
from sympy.utilities.decorator import doctest_depends_on
|
| 3 |
+
|
| 4 |
+
from sympy.parsing.latex.lark import LarkLaTeXParser, TransformToSymPyExpr, parse_latex_lark # noqa
|
| 5 |
+
|
| 6 |
+
from .errors import LaTeXParsingError # noqa
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
__doctest_requires__ = {('parse_latex',): ['antlr4', 'lark']}
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
@doctest_depends_on(modules=('antlr4', 'lark'))
|
| 13 |
+
def parse_latex(s, strict=False, backend="antlr"):
|
| 14 |
+
r"""Converts the input LaTeX string ``s`` to a SymPy ``Expr``.
|
| 15 |
+
|
| 16 |
+
Parameters
|
| 17 |
+
==========
|
| 18 |
+
|
| 19 |
+
s : str
|
| 20 |
+
The LaTeX string to parse. In Python source containing LaTeX,
|
| 21 |
+
*raw strings* (denoted with ``r"``, like this one) are preferred,
|
| 22 |
+
as LaTeX makes liberal use of the ``\`` character, which would
|
| 23 |
+
trigger escaping in normal Python strings.
|
| 24 |
+
backend : str, optional
|
| 25 |
+
Currently, there are two backends supported: ANTLR, and Lark.
|
| 26 |
+
The default setting is to use the ANTLR backend, which can be
|
| 27 |
+
changed to Lark if preferred.
|
| 28 |
+
|
| 29 |
+
Use ``backend="antlr"`` for the ANTLR-based parser, and
|
| 30 |
+
``backend="lark"`` for the Lark-based parser.
|
| 31 |
+
|
| 32 |
+
The ``backend`` option is case-sensitive, and must be in
|
| 33 |
+
all lowercase.
|
| 34 |
+
strict : bool, optional
|
| 35 |
+
This option is only available with the ANTLR backend.
|
| 36 |
+
|
| 37 |
+
If True, raise an exception if the string cannot be parsed as
|
| 38 |
+
valid LaTeX. If False, try to recover gracefully from common
|
| 39 |
+
mistakes.
|
| 40 |
+
|
| 41 |
+
Examples
|
| 42 |
+
========
|
| 43 |
+
|
| 44 |
+
>>> from sympy.parsing.latex import parse_latex
|
| 45 |
+
>>> expr = parse_latex(r"\frac {1 + \sqrt {\a}} {\b}")
|
| 46 |
+
>>> expr
|
| 47 |
+
(sqrt(a) + 1)/b
|
| 48 |
+
>>> expr.evalf(4, subs=dict(a=5, b=2))
|
| 49 |
+
1.618
|
| 50 |
+
>>> func = parse_latex(r"\int_1^\alpha \dfrac{\mathrm{d}t}{t}", backend="lark")
|
| 51 |
+
>>> func.evalf(subs={"alpha": 2})
|
| 52 |
+
0.693147180559945
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
if backend == "antlr":
|
| 56 |
+
_latex = import_module(
|
| 57 |
+
'sympy.parsing.latex._parse_latex_antlr',
|
| 58 |
+
import_kwargs={'fromlist': ['X']})
|
| 59 |
+
|
| 60 |
+
if _latex is not None:
|
| 61 |
+
return _latex.parse_latex(s, strict)
|
| 62 |
+
elif backend == "lark":
|
| 63 |
+
return parse_latex_lark(s)
|
| 64 |
+
else:
|
| 65 |
+
raise NotImplementedError(f"Using the '{backend}' backend in the LaTeX" \
|
| 66 |
+
" parser is not supported.")
|
lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (2.63 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/_build_latex_antlr.cpython-312.pyc
ADDED
|
Binary file (4.6 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/_parse_latex_antlr.cpython-312.pyc
ADDED
|
Binary file (31.6 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/latex/__pycache__/errors.cpython-312.pyc
ADDED
|
Binary file (390 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/parsing/latex/_antlr/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
| 2 |
+
#
|
| 3 |
+
# Generated from ../LaTeX.g4, derived from latex2sympy
|
| 4 |
+
# latex2sympy is licensed under the MIT license
|
| 5 |
+
# https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt
|
| 6 |
+
#
|
| 7 |
+
# Generated with antlr4
|
| 8 |
+
# antlr4 is licensed under the BSD-3-Clause License
|
| 9 |
+
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
lib/python3.12/site-packages/sympy/parsing/latex/_antlr/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (205 Bytes). View file
|
|
|