onnxslim 0.1.80__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- onnxslim/__init__.py +16 -0
- onnxslim/__main__.py +4 -0
- onnxslim/argparser.py +215 -0
- onnxslim/cli/__init__.py +1 -0
- onnxslim/cli/_main.py +180 -0
- onnxslim/core/__init__.py +219 -0
- onnxslim/core/optimization/__init__.py +146 -0
- onnxslim/core/optimization/dead_node_elimination.py +151 -0
- onnxslim/core/optimization/subexpression_elimination.py +76 -0
- onnxslim/core/optimization/weight_tying.py +59 -0
- onnxslim/core/pattern/__init__.py +249 -0
- onnxslim/core/pattern/elimination/__init__.py +5 -0
- onnxslim/core/pattern/elimination/concat.py +61 -0
- onnxslim/core/pattern/elimination/reshape.py +77 -0
- onnxslim/core/pattern/elimination/reshape_as.py +64 -0
- onnxslim/core/pattern/elimination/slice.py +108 -0
- onnxslim/core/pattern/elimination/unsqueeze.py +92 -0
- onnxslim/core/pattern/fusion/__init__.py +8 -0
- onnxslim/core/pattern/fusion/concat_reshape.py +50 -0
- onnxslim/core/pattern/fusion/convadd.py +70 -0
- onnxslim/core/pattern/fusion/convbn.py +86 -0
- onnxslim/core/pattern/fusion/convmul.py +69 -0
- onnxslim/core/pattern/fusion/gelu.py +47 -0
- onnxslim/core/pattern/fusion/gemm.py +330 -0
- onnxslim/core/pattern/fusion/padconv.py +89 -0
- onnxslim/core/pattern/fusion/reduce.py +67 -0
- onnxslim/core/pattern/registry.py +28 -0
- onnxslim/misc/__init__.py +0 -0
- onnxslim/misc/tabulate.py +2681 -0
- onnxslim/third_party/__init__.py +0 -0
- onnxslim/third_party/_sympy/__init__.py +0 -0
- onnxslim/third_party/_sympy/functions.py +205 -0
- onnxslim/third_party/_sympy/numbers.py +397 -0
- onnxslim/third_party/_sympy/printers.py +491 -0
- onnxslim/third_party/_sympy/solve.py +172 -0
- onnxslim/third_party/_sympy/symbol.py +102 -0
- onnxslim/third_party/onnx_graphsurgeon/__init__.py +15 -0
- onnxslim/third_party/onnx_graphsurgeon/exporters/__init__.py +1 -0
- onnxslim/third_party/onnx_graphsurgeon/exporters/base_exporter.py +33 -0
- onnxslim/third_party/onnx_graphsurgeon/exporters/onnx_exporter.py +432 -0
- onnxslim/third_party/onnx_graphsurgeon/graph_pattern/__init__.py +4 -0
- onnxslim/third_party/onnx_graphsurgeon/graph_pattern/graph_pattern.py +466 -0
- onnxslim/third_party/onnx_graphsurgeon/importers/__init__.py +1 -0
- onnxslim/third_party/onnx_graphsurgeon/importers/base_importer.py +33 -0
- onnxslim/third_party/onnx_graphsurgeon/importers/onnx_importer.py +558 -0
- onnxslim/third_party/onnx_graphsurgeon/ir/__init__.py +0 -0
- onnxslim/third_party/onnx_graphsurgeon/ir/function.py +274 -0
- onnxslim/third_party/onnx_graphsurgeon/ir/graph.py +1575 -0
- onnxslim/third_party/onnx_graphsurgeon/ir/node.py +266 -0
- onnxslim/third_party/onnx_graphsurgeon/ir/tensor.py +504 -0
- onnxslim/third_party/onnx_graphsurgeon/logger/__init__.py +1 -0
- onnxslim/third_party/onnx_graphsurgeon/logger/logger.py +261 -0
- onnxslim/third_party/onnx_graphsurgeon/util/__init__.py +0 -0
- onnxslim/third_party/onnx_graphsurgeon/util/exception.py +20 -0
- onnxslim/third_party/onnx_graphsurgeon/util/misc.py +252 -0
- onnxslim/third_party/symbolic_shape_infer.py +3273 -0
- onnxslim/utils.py +794 -0
- onnxslim/version.py +1 -0
- onnxslim-0.1.80.dist-info/METADATA +207 -0
- onnxslim-0.1.80.dist-info/RECORD +65 -0
- onnxslim-0.1.80.dist-info/WHEEL +5 -0
- onnxslim-0.1.80.dist-info/entry_points.txt +2 -0
- onnxslim-0.1.80.dist-info/licenses/LICENSE +21 -0
- onnxslim-0.1.80.dist-info/top_level.txt +1 -0
- onnxslim-0.1.80.dist-info/zip-safe +1 -0
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# mypy: allow-untyped-defs
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import functools
|
|
5
|
+
import math
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
import sympy
|
|
9
|
+
from sympy.core.numbers import equal_valued
|
|
10
|
+
from sympy.printing.precedence import PRECEDENCE
|
|
11
|
+
|
|
12
|
+
from .numbers import int_oo
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from collections.abc import Iterable
|
|
16
|
+
|
|
17
|
+
# Portions of this file are adapted from the Sympy codebase, which was
|
|
18
|
+
# licensed as follows:
|
|
19
|
+
#
|
|
20
|
+
# Copyright (c) 2006-2023 SymPy Development Team
|
|
21
|
+
#
|
|
22
|
+
# All rights reserved.
|
|
23
|
+
#
|
|
24
|
+
# Redistribution and use in source and binary forms, with or without
|
|
25
|
+
# modification, are permitted provided that the following conditions are met:
|
|
26
|
+
#
|
|
27
|
+
# a. Redistributions of source code must retain the above copyright notice,
|
|
28
|
+
# this list of conditions and the following disclaimer.
|
|
29
|
+
# b. Redistributions in binary form must reproduce the above copyright
|
|
30
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
31
|
+
# documentation and/or other materials provided with the distribution.
|
|
32
|
+
# c. Neither the name of SymPy nor the names of its contributors
|
|
33
|
+
# may be used to endorse or promote products derived from this software
|
|
34
|
+
# without specific prior written permission.
|
|
35
|
+
#
|
|
36
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
37
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
38
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
39
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
|
40
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
41
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
42
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
43
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
44
|
+
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
45
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
46
|
+
# DAMAGE.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def simple_floordiv_gcd(p: sympy.Basic, q: sympy.Basic) -> sympy.Basic:
|
|
50
|
+
"""
|
|
51
|
+
Fast path for sympy.gcd, using a simple factoring strategy.
|
|
52
|
+
|
|
53
|
+
We try to rewrite p and q in the form n*e*p1 + n*e*p2 and n*e*q0, where n is the greatest common integer factor and
|
|
54
|
+
e is the largest syntactic common factor (i.e., common sub-expression) in p and q. Then the gcd returned is n*e,
|
|
55
|
+
canceling which we would be left with p1 + p2 and q0.
|
|
56
|
+
|
|
57
|
+
Note that further factoring of p1 + p2 and q0 might be possible with sympy.factor (which uses domain-specific
|
|
58
|
+
theories). E.g., we are unable to find that x*y + x + y + 1 is divisible by x + 1. More generally, when q is of the
|
|
59
|
+
form q1 + q2 (instead of being already factored) it might be necessary to fall back on sympy.gcd.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def integer_coefficient(x: sympy.Basic) -> int:
|
|
63
|
+
integer_coefficients: list[int] = [
|
|
64
|
+
abs(int(arg)) for arg in sympy.Mul.make_args(x) if isinstance(arg, (int, sympy.Integer))
|
|
65
|
+
]
|
|
66
|
+
return math.prod(integer_coefficients)
|
|
67
|
+
|
|
68
|
+
def integer_factor(expr: sympy.Basic) -> int:
|
|
69
|
+
integer_factors: Iterable[int] = map(integer_coefficient, sympy.Add.make_args(expr))
|
|
70
|
+
return functools.reduce(math.gcd, integer_factors)
|
|
71
|
+
|
|
72
|
+
gcd: int = math.gcd(integer_factor(p), integer_factor(q))
|
|
73
|
+
p, q = p / gcd, q / gcd # type: ignore[operator, assignment] # remove in py3.12
|
|
74
|
+
|
|
75
|
+
base_splits: list[tuple[sympy.Basic, ...]] = list(map(sympy.Mul.make_args, sympy.Add.make_args(p)))
|
|
76
|
+
divisor_split: tuple[sympy.Basic, ...] = sympy.Mul.make_args(q)
|
|
77
|
+
for x in divisor_split:
|
|
78
|
+
if all(x in base_split for base_split in base_splits):
|
|
79
|
+
gcd = gcd * x # type: ignore[operator] # remove in py3.12
|
|
80
|
+
return gcd # type: ignore[return-value] # remove in py3.12
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# It would be nice to have assertions on whether or not inputs is_integer
|
|
84
|
+
# However, with bugs like https://github.com/sympy/sympy/issues/26620 sympy
|
|
85
|
+
# sometimes inconsistently reports floats an integers.
|
|
86
|
+
#
|
|
87
|
+
# What we can assume from sympy is that if something is an int, it
|
|
88
|
+
# definitely is is_integer, but if it is a float it may or may not
|
|
89
|
+
# be is_integer. So we are unable to do strong asserts that things
|
|
90
|
+
# are NOT integers.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# TODO: In Triton, // rounds to zero, but in Python, it is floor division.
|
|
94
|
+
# When we can prove both arguments are non-negative, we should just have a
|
|
95
|
+
# GenericFloorDiv (name pending) which can codegen efficiently in Python/C,
|
|
96
|
+
# and then PythonFloorDiv and CIntDiv which have the appropriate rounding
|
|
97
|
+
# semantics.
|
|
98
|
+
#
|
|
99
|
+
# Right now, FloorDiv de facto changes behavior if arguments are negative or
|
|
100
|
+
# not, this can potentially cause correctness issues.
|
|
101
|
+
class FloorDiv(sympy.Function):
|
|
102
|
+
"""
|
|
103
|
+
We maintain this so that:
|
|
104
|
+
1. We can use divisibility guards to simplify FloorDiv(a, b) to a / b.
|
|
105
|
+
2. Printing out the expression is nicer (compared to say, representing a//b as (a - a % b) / b).
|
|
106
|
+
|
|
107
|
+
NB: This is Python-style floor division, round to -Inf
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
nargs: tuple[int, ...] = (2,)
|
|
111
|
+
precedence: int = 35 # lower precedence than add
|
|
112
|
+
is_integer: bool = True
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def base(self) -> sympy.Basic:
|
|
116
|
+
return self.args[0]
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def divisor(self) -> sympy.Basic:
|
|
120
|
+
return self.args[1]
|
|
121
|
+
|
|
122
|
+
def _sympystr(self, printer: sympy.printing.StrPrinter) -> str:
|
|
123
|
+
base = printer.parenthesize(self.base, PRECEDENCE["Atom"] - 0.5)
|
|
124
|
+
divisor = printer.parenthesize(self.divisor, PRECEDENCE["Atom"] - 0.5)
|
|
125
|
+
return f"({base}//{divisor})"
|
|
126
|
+
|
|
127
|
+
# Automatic evaluation.
|
|
128
|
+
# https://docs.sympy.org/latest/guides/custom-functions.html#best-practices-for-eval
|
|
129
|
+
@classmethod
|
|
130
|
+
def eval(cls, base: sympy.Integer, divisor: sympy.Integer) -> sympy.Basic | None:
|
|
131
|
+
# python test/test_dynamic_shapes.py -k TestDimConstraints.test_dim_constraints_solve_full
|
|
132
|
+
# Assert triggered by inequality solver
|
|
133
|
+
# assert base.is_integer, base
|
|
134
|
+
# assert divisor.is_integer, divisor
|
|
135
|
+
|
|
136
|
+
# We don't provide the same error message as in Python because SymPy
|
|
137
|
+
# makes it difficult to check the types.
|
|
138
|
+
if divisor.is_zero:
|
|
139
|
+
raise ZeroDivisionError("division by zero")
|
|
140
|
+
if base in (int_oo, -int_oo, sympy.oo, -sympy.oo) and divisor in (
|
|
141
|
+
int_oo,
|
|
142
|
+
-int_oo,
|
|
143
|
+
sympy.oo,
|
|
144
|
+
-sympy.oo,
|
|
145
|
+
):
|
|
146
|
+
return sympy.nan
|
|
147
|
+
if base is sympy.nan or divisor is sympy.nan:
|
|
148
|
+
return sympy.nan
|
|
149
|
+
|
|
150
|
+
if base.is_zero:
|
|
151
|
+
return sympy.S.Zero
|
|
152
|
+
if base.is_integer and equal_valued(divisor, 1):
|
|
153
|
+
return base
|
|
154
|
+
if base.is_integer and equal_valued(divisor, -1):
|
|
155
|
+
return sympy.Mul(base, -1)
|
|
156
|
+
if (
|
|
157
|
+
isinstance(base, sympy.Number)
|
|
158
|
+
and isinstance(divisor, sympy.Number)
|
|
159
|
+
and (base in (int_oo, -int_oo, sympy.oo, -sympy.oo) or divisor in (int_oo, -int_oo, sympy.oo, -sympy.oo))
|
|
160
|
+
):
|
|
161
|
+
r = float(base) / float(divisor)
|
|
162
|
+
if r == math.inf:
|
|
163
|
+
return int_oo
|
|
164
|
+
elif r == -math.inf:
|
|
165
|
+
return -int_oo
|
|
166
|
+
elif math.isnan(r):
|
|
167
|
+
return sympy.nan
|
|
168
|
+
else:
|
|
169
|
+
return sympy.Integer(math.floor(r))
|
|
170
|
+
if isinstance(base, sympy.Integer) and isinstance(divisor, sympy.Integer):
|
|
171
|
+
return sympy.Integer(int(base) // int(divisor))
|
|
172
|
+
if isinstance(base, FloorDiv):
|
|
173
|
+
return FloorDiv(base.args[0], base.args[1] * divisor)
|
|
174
|
+
|
|
175
|
+
# Expands (x + y) // b into x // b + y // b.
|
|
176
|
+
# This only works if floor is an identity, i.e. x / b is an integer.
|
|
177
|
+
if isinstance(divisor, sympy.Integer):
|
|
178
|
+
quotients = 0
|
|
179
|
+
terms = []
|
|
180
|
+
for term in sympy.Add.make_args(base):
|
|
181
|
+
quotient = term / divisor
|
|
182
|
+
|
|
183
|
+
if quotient.is_integer:
|
|
184
|
+
terms.append(term)
|
|
185
|
+
quotients += quotient
|
|
186
|
+
|
|
187
|
+
if len(terms) != 0:
|
|
188
|
+
# Passing evaluate = False since expression will be optimized during the subtraction post its construction.
|
|
189
|
+
return FloorDiv(base - sympy.Add(*terms, evaluate=False), divisor) + quotients
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
gcd = simple_floordiv_gcd(base, divisor)
|
|
193
|
+
if equal_valued(gcd, 1) and isinstance(divisor, sympy.Add):
|
|
194
|
+
gcd = sympy.gcd(base, divisor)
|
|
195
|
+
if not equal_valued(gcd, 1):
|
|
196
|
+
return FloorDiv(sympy.simplify(base / gcd), sympy.simplify(divisor / gcd))
|
|
197
|
+
except sympy.PolynomialError:
|
|
198
|
+
pass # https://github.com/pytorch/pytorch/issues/108276
|
|
199
|
+
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
def _ccode(self, printer):
|
|
203
|
+
base = printer.parenthesize(self.base, PRECEDENCE["Atom"] - 0.5)
|
|
204
|
+
divisor = printer.parenthesize(self.divisor, PRECEDENCE["Atom"] - 0.5)
|
|
205
|
+
return f"floor({base}/{divisor})"
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# mypy: allow-untyped-defs
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import mpmath.libmp as mlib # type: ignore[import-untyped]
|
|
5
|
+
import sympy
|
|
6
|
+
from sympy import Expr
|
|
7
|
+
from sympy.core.decorators import _sympifyit
|
|
8
|
+
from sympy.core.expr import AtomicExpr
|
|
9
|
+
from sympy.core.numbers import Number
|
|
10
|
+
from sympy.core.parameters import global_parameters
|
|
11
|
+
from sympy.core.singleton import S, Singleton
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IntInfinitySlim(Number, metaclass=Singleton):
|
|
15
|
+
r"""
|
|
16
|
+
Positive integer infinite quantity.
|
|
17
|
+
|
|
18
|
+
Integer infinity is a value in an extended integers which
|
|
19
|
+
is greater than all other integers. We distinguish it from
|
|
20
|
+
sympy's existing notion of infinity in that it reports that
|
|
21
|
+
it is_integer.
|
|
22
|
+
|
|
23
|
+
Infinity is a singleton, and can be accessed by ``S.IntInfinitySlim``,
|
|
24
|
+
or can be imported as ``int_oo``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# NB: We can't actually mark this as infinite, as integer and infinite are
|
|
28
|
+
# inconsistent assumptions in sympy. We also report that we are complex,
|
|
29
|
+
# different from sympy.oo
|
|
30
|
+
|
|
31
|
+
is_integer = True
|
|
32
|
+
is_commutative = True
|
|
33
|
+
is_number = True
|
|
34
|
+
is_extended_real = True
|
|
35
|
+
is_comparable = True
|
|
36
|
+
is_extended_positive = True
|
|
37
|
+
is_prime = False
|
|
38
|
+
|
|
39
|
+
# Ensure we get dispatched to before plain numbers
|
|
40
|
+
_op_priority = 100.0
|
|
41
|
+
|
|
42
|
+
__slots__ = ()
|
|
43
|
+
|
|
44
|
+
def __new__(cls):
|
|
45
|
+
return AtomicExpr.__new__(cls)
|
|
46
|
+
|
|
47
|
+
def _sympystr(self, printer):
|
|
48
|
+
return "int_oo"
|
|
49
|
+
|
|
50
|
+
def _eval_subs(self, old, new):
|
|
51
|
+
if self == old:
|
|
52
|
+
return new
|
|
53
|
+
|
|
54
|
+
# We could do these, not sure about it
|
|
55
|
+
"""
|
|
56
|
+
def _eval_evalf(self, prec=None):
|
|
57
|
+
return Float('inf')
|
|
58
|
+
|
|
59
|
+
def evalf(self, prec=None, **options):
|
|
60
|
+
return self._eval_evalf(prec)
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
@_sympifyit("other", NotImplemented)
|
|
64
|
+
def __add__(self, other):
|
|
65
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
66
|
+
if other in (S.Infinity, S.NegativeInfinity):
|
|
67
|
+
return other
|
|
68
|
+
if other in (S.NegativeIntInfinitySlim, S.NaN):
|
|
69
|
+
return S.NaN
|
|
70
|
+
return self
|
|
71
|
+
return Number.__add__(self, other)
|
|
72
|
+
|
|
73
|
+
__radd__ = __add__
|
|
74
|
+
|
|
75
|
+
@_sympifyit("other", NotImplemented)
|
|
76
|
+
def __sub__(self, other):
|
|
77
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
78
|
+
if other is S.Infinity:
|
|
79
|
+
return S.NegativeInfinity
|
|
80
|
+
if other is S.NegativeInfinity:
|
|
81
|
+
return S.Infinity
|
|
82
|
+
if other in (S.IntInfinitySlim, S.NaN):
|
|
83
|
+
return S.NaN
|
|
84
|
+
return self
|
|
85
|
+
return Number.__sub__(self, other)
|
|
86
|
+
|
|
87
|
+
@_sympifyit("other", NotImplemented)
|
|
88
|
+
def __rsub__(self, other):
|
|
89
|
+
return (-self).__add__(other)
|
|
90
|
+
|
|
91
|
+
@_sympifyit("other", NotImplemented)
|
|
92
|
+
def __mul__(self, other):
|
|
93
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
94
|
+
if other.is_zero or other is S.NaN:
|
|
95
|
+
return S.NaN
|
|
96
|
+
if other.is_extended_positive:
|
|
97
|
+
return self
|
|
98
|
+
return S.NegativeIntInfinitySlim
|
|
99
|
+
return Number.__mul__(self, other)
|
|
100
|
+
|
|
101
|
+
__rmul__ = __mul__
|
|
102
|
+
|
|
103
|
+
@_sympifyit("other", NotImplemented)
|
|
104
|
+
def __truediv__(self, other):
|
|
105
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
106
|
+
if other in (
|
|
107
|
+
S.Infinity,
|
|
108
|
+
S.IntInfinitySlim,
|
|
109
|
+
S.NegativeInfinity,
|
|
110
|
+
S.NegativeIntInfinitySlim,
|
|
111
|
+
S.NaN,
|
|
112
|
+
):
|
|
113
|
+
return S.NaN
|
|
114
|
+
if other.is_extended_nonnegative:
|
|
115
|
+
return S.Infinity # truediv produces float
|
|
116
|
+
return S.NegativeInfinity # truediv produces float
|
|
117
|
+
return Number.__truediv__(self, other)
|
|
118
|
+
|
|
119
|
+
def __abs__(self):
|
|
120
|
+
return S.IntInfinitySlim
|
|
121
|
+
|
|
122
|
+
def __neg__(self):
|
|
123
|
+
return S.NegativeIntInfinitySlim
|
|
124
|
+
|
|
125
|
+
def _eval_power(self, expt):
|
|
126
|
+
if expt.is_extended_positive:
|
|
127
|
+
return S.IntInfinitySlim
|
|
128
|
+
if expt.is_extended_negative:
|
|
129
|
+
return S.Zero
|
|
130
|
+
if expt is S.NaN:
|
|
131
|
+
return S.NaN
|
|
132
|
+
if expt is S.ComplexInfinity:
|
|
133
|
+
return S.NaN
|
|
134
|
+
if expt.is_extended_real is False and expt.is_number:
|
|
135
|
+
from sympy.functions.elementary.complexes import re
|
|
136
|
+
|
|
137
|
+
expt_real = re(expt)
|
|
138
|
+
if expt_real.is_positive:
|
|
139
|
+
return S.ComplexInfinity
|
|
140
|
+
if expt_real.is_negative:
|
|
141
|
+
return S.Zero
|
|
142
|
+
if expt_real.is_zero:
|
|
143
|
+
return S.NaN
|
|
144
|
+
|
|
145
|
+
return self ** expt.evalf()
|
|
146
|
+
|
|
147
|
+
def _as_mpf_val(self, prec):
|
|
148
|
+
return mlib.finf
|
|
149
|
+
|
|
150
|
+
def __hash__(self):
|
|
151
|
+
return super().__hash__()
|
|
152
|
+
|
|
153
|
+
def __eq__(self, other):
|
|
154
|
+
return other is S.IntInfinitySlim
|
|
155
|
+
|
|
156
|
+
def __ne__(self, other):
|
|
157
|
+
return other is not S.IntInfinitySlim
|
|
158
|
+
|
|
159
|
+
def __gt__(self, other):
|
|
160
|
+
if other is S.Infinity:
|
|
161
|
+
return sympy.false # sympy.oo > int_oo
|
|
162
|
+
elif other is S.IntInfinitySlim:
|
|
163
|
+
return sympy.false # consistency with sympy.oo
|
|
164
|
+
else:
|
|
165
|
+
return sympy.true
|
|
166
|
+
|
|
167
|
+
def __ge__(self, other):
|
|
168
|
+
if other is S.Infinity:
|
|
169
|
+
return sympy.false # sympy.oo > int_oo
|
|
170
|
+
elif other is S.IntInfinitySlim:
|
|
171
|
+
return sympy.true # consistency with sympy.oo
|
|
172
|
+
else:
|
|
173
|
+
return sympy.true
|
|
174
|
+
|
|
175
|
+
def __lt__(self, other):
|
|
176
|
+
if other is S.Infinity:
|
|
177
|
+
return sympy.true # sympy.oo > int_oo
|
|
178
|
+
elif other is S.IntInfinitySlim:
|
|
179
|
+
return sympy.false # consistency with sympy.oo
|
|
180
|
+
else:
|
|
181
|
+
return sympy.false
|
|
182
|
+
|
|
183
|
+
def __le__(self, other):
|
|
184
|
+
if other is S.Infinity:
|
|
185
|
+
return sympy.true # sympy.oo > int_oo
|
|
186
|
+
elif other is S.IntInfinitySlim:
|
|
187
|
+
return sympy.true # consistency with sympy.oo
|
|
188
|
+
else:
|
|
189
|
+
return sympy.false
|
|
190
|
+
|
|
191
|
+
@_sympifyit("other", NotImplemented)
|
|
192
|
+
def __mod__(self, other):
|
|
193
|
+
if not isinstance(other, Expr):
|
|
194
|
+
return NotImplemented
|
|
195
|
+
return S.NaN
|
|
196
|
+
|
|
197
|
+
__rmod__ = __mod__
|
|
198
|
+
|
|
199
|
+
def floor(self):
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
def ceiling(self):
|
|
203
|
+
return self
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
int_oo = S.IntInfinitySlim
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class NegativeIntInfinitySlim(Number, metaclass=Singleton):
|
|
210
|
+
"""
|
|
211
|
+
Negative integer infinite quantity.
|
|
212
|
+
|
|
213
|
+
NegativeInfinity is a singleton, and can be accessed
|
|
214
|
+
by ``S.NegativeInfinity``.
|
|
215
|
+
|
|
216
|
+
See Also
|
|
217
|
+
========
|
|
218
|
+
|
|
219
|
+
IntInfinitySlim
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
# Ensure we get dispatched to before plain numbers
|
|
223
|
+
_op_priority = 100.0
|
|
224
|
+
|
|
225
|
+
is_integer = True
|
|
226
|
+
is_extended_real = True
|
|
227
|
+
is_commutative = True
|
|
228
|
+
is_comparable = True
|
|
229
|
+
is_extended_negative = True
|
|
230
|
+
is_number = True
|
|
231
|
+
is_prime = False
|
|
232
|
+
|
|
233
|
+
__slots__ = ()
|
|
234
|
+
|
|
235
|
+
def __new__(cls):
|
|
236
|
+
return AtomicExpr.__new__(cls)
|
|
237
|
+
|
|
238
|
+
def _eval_subs(self, old, new):
|
|
239
|
+
if self == old:
|
|
240
|
+
return new
|
|
241
|
+
|
|
242
|
+
def _sympystr(self, printer):
|
|
243
|
+
return "-int_oo"
|
|
244
|
+
|
|
245
|
+
"""
|
|
246
|
+
def _eval_evalf(self, prec=None):
|
|
247
|
+
return Float('-inf')
|
|
248
|
+
|
|
249
|
+
def evalf(self, prec=None, **options):
|
|
250
|
+
return self._eval_evalf(prec)
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
@_sympifyit("other", NotImplemented)
|
|
254
|
+
def __add__(self, other):
|
|
255
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
256
|
+
if other is S.Infinity:
|
|
257
|
+
return S.Infinity
|
|
258
|
+
if other in (S.IntInfinitySlim, S.NaN):
|
|
259
|
+
return S.NaN
|
|
260
|
+
return self
|
|
261
|
+
return Number.__add__(self, other)
|
|
262
|
+
|
|
263
|
+
__radd__ = __add__
|
|
264
|
+
|
|
265
|
+
@_sympifyit("other", NotImplemented)
|
|
266
|
+
def __sub__(self, other):
|
|
267
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
268
|
+
if other is S.NegativeInfinity:
|
|
269
|
+
return S.Infinity
|
|
270
|
+
if other in (S.NegativeIntInfinitySlim, S.NaN):
|
|
271
|
+
return S.NaN
|
|
272
|
+
return self
|
|
273
|
+
return Number.__sub__(self, other)
|
|
274
|
+
|
|
275
|
+
@_sympifyit("other", NotImplemented)
|
|
276
|
+
def __rsub__(self, other):
|
|
277
|
+
return (-self).__add__(other)
|
|
278
|
+
|
|
279
|
+
@_sympifyit("other", NotImplemented)
|
|
280
|
+
def __mul__(self, other):
|
|
281
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
282
|
+
if other.is_zero or other is S.NaN:
|
|
283
|
+
return S.NaN
|
|
284
|
+
if other.is_extended_positive:
|
|
285
|
+
return self
|
|
286
|
+
return S.IntInfinitySlim
|
|
287
|
+
return Number.__mul__(self, other)
|
|
288
|
+
|
|
289
|
+
__rmul__ = __mul__
|
|
290
|
+
|
|
291
|
+
@_sympifyit("other", NotImplemented)
|
|
292
|
+
def __truediv__(self, other):
|
|
293
|
+
if isinstance(other, Number) and global_parameters.evaluate:
|
|
294
|
+
if other in (
|
|
295
|
+
S.Infinity,
|
|
296
|
+
S.IntInfinitySlim,
|
|
297
|
+
S.NegativeInfinity,
|
|
298
|
+
S.NegativeIntInfinitySlim,
|
|
299
|
+
S.NaN,
|
|
300
|
+
):
|
|
301
|
+
return S.NaN
|
|
302
|
+
if other.is_extended_nonnegative:
|
|
303
|
+
return self
|
|
304
|
+
return S.Infinity # truediv returns float
|
|
305
|
+
return Number.__truediv__(self, other)
|
|
306
|
+
|
|
307
|
+
def __abs__(self):
|
|
308
|
+
return S.IntInfinitySlim
|
|
309
|
+
|
|
310
|
+
def __neg__(self):
|
|
311
|
+
return S.IntInfinitySlim
|
|
312
|
+
|
|
313
|
+
def _eval_power(self, expt):
|
|
314
|
+
if expt.is_number:
|
|
315
|
+
if expt in (
|
|
316
|
+
S.NaN,
|
|
317
|
+
S.Infinity,
|
|
318
|
+
S.NegativeInfinity,
|
|
319
|
+
S.IntInfinitySlim,
|
|
320
|
+
S.NegativeIntInfinitySlim,
|
|
321
|
+
):
|
|
322
|
+
return S.NaN
|
|
323
|
+
|
|
324
|
+
if isinstance(expt, sympy.Integer) and expt.is_extended_positive:
|
|
325
|
+
if expt.is_odd:
|
|
326
|
+
return S.NegativeIntInfinitySlim
|
|
327
|
+
else:
|
|
328
|
+
return S.IntInfinitySlim
|
|
329
|
+
|
|
330
|
+
inf_part = S.IntInfinitySlim**expt
|
|
331
|
+
s_part = S.NegativeOne**expt
|
|
332
|
+
if inf_part == 0 and s_part.is_finite:
|
|
333
|
+
return inf_part
|
|
334
|
+
if inf_part is S.ComplexInfinity and s_part.is_finite and not s_part.is_zero:
|
|
335
|
+
return S.ComplexInfinity
|
|
336
|
+
return s_part * inf_part
|
|
337
|
+
|
|
338
|
+
def _as_mpf_val(self, prec):
|
|
339
|
+
return mlib.fninf
|
|
340
|
+
|
|
341
|
+
def __hash__(self):
|
|
342
|
+
return super().__hash__()
|
|
343
|
+
|
|
344
|
+
def __eq__(self, other):
|
|
345
|
+
return other is S.NegativeIntInfinitySlim
|
|
346
|
+
|
|
347
|
+
def __ne__(self, other):
|
|
348
|
+
return other is not S.NegativeIntInfinitySlim
|
|
349
|
+
|
|
350
|
+
def __gt__(self, other):
|
|
351
|
+
if other is S.NegativeInfinity:
|
|
352
|
+
return sympy.true # -sympy.oo < -int_oo
|
|
353
|
+
elif other is S.NegativeIntInfinitySlim:
|
|
354
|
+
return sympy.false # consistency with sympy.oo
|
|
355
|
+
else:
|
|
356
|
+
return sympy.false
|
|
357
|
+
|
|
358
|
+
def __ge__(self, other):
|
|
359
|
+
if other is S.NegativeInfinity:
|
|
360
|
+
return sympy.true # -sympy.oo < -int_oo
|
|
361
|
+
elif other is S.NegativeIntInfinitySlim:
|
|
362
|
+
return sympy.true # consistency with sympy.oo
|
|
363
|
+
else:
|
|
364
|
+
return sympy.false
|
|
365
|
+
|
|
366
|
+
def __lt__(self, other):
|
|
367
|
+
if other is S.NegativeInfinity:
|
|
368
|
+
return sympy.false # -sympy.oo < -int_oo
|
|
369
|
+
elif other is S.NegativeIntInfinitySlim:
|
|
370
|
+
return sympy.false # consistency with sympy.oo
|
|
371
|
+
else:
|
|
372
|
+
return sympy.true
|
|
373
|
+
|
|
374
|
+
def __le__(self, other):
|
|
375
|
+
if other is S.NegativeInfinity:
|
|
376
|
+
return sympy.false # -sympy.oo < -int_oo
|
|
377
|
+
elif other is S.NegativeIntInfinitySlim:
|
|
378
|
+
return sympy.true # consistency with sympy.oo
|
|
379
|
+
else:
|
|
380
|
+
return sympy.true
|
|
381
|
+
|
|
382
|
+
@_sympifyit("other", NotImplemented)
|
|
383
|
+
def __mod__(self, other):
|
|
384
|
+
if not isinstance(other, Expr):
|
|
385
|
+
return NotImplemented
|
|
386
|
+
return S.NaN
|
|
387
|
+
|
|
388
|
+
__rmod__ = __mod__
|
|
389
|
+
|
|
390
|
+
def floor(self):
|
|
391
|
+
return self
|
|
392
|
+
|
|
393
|
+
def ceiling(self):
|
|
394
|
+
return self
|
|
395
|
+
|
|
396
|
+
def as_powers_dict(self):
|
|
397
|
+
return {S.NegativeOne: 1, S.IntInfinitySlim: 1}
|