397 lines
11 KiB
Python
397 lines
11 KiB
Python
# mypy: allow-untyped-defs
|
|
import mpmath.libmp as mlib # type: ignore[import-untyped]
|
|
import sympy
|
|
from sympy import Expr
|
|
from sympy.core.decorators import _sympifyit
|
|
from sympy.core.expr import AtomicExpr
|
|
from sympy.core.numbers import Number
|
|
from sympy.core.parameters import global_parameters
|
|
from sympy.core.singleton import S, Singleton
|
|
|
|
|
|
class IntInfinity(Number, metaclass=Singleton):
|
|
r"""Positive integer infinite quantity.
|
|
|
|
Integer infinity is a value in an extended integers which
|
|
is greater than all other integers. We distinguish it from
|
|
sympy's existing notion of infinity in that it reports that
|
|
it is_integer.
|
|
|
|
Infinity is a singleton, and can be accessed by ``S.IntInfinity``,
|
|
or can be imported as ``int_oo``.
|
|
"""
|
|
|
|
# NB: We can't actually mark this as infinite, as integer and infinite are
|
|
# inconsistent assumptions in sympy. We also report that we are complex,
|
|
# different from sympy.oo
|
|
|
|
is_integer = True
|
|
is_commutative = True
|
|
is_number = True
|
|
is_extended_real = True
|
|
is_comparable = True
|
|
is_extended_positive = True
|
|
is_prime = False
|
|
|
|
# Ensure we get dispatched to before plain numbers
|
|
_op_priority = 100.0
|
|
|
|
__slots__ = ()
|
|
|
|
def __new__(cls):
|
|
return AtomicExpr.__new__(cls)
|
|
|
|
def _sympystr(self, printer):
|
|
return "int_oo"
|
|
|
|
def _eval_subs(self, old, new):
|
|
if self == old:
|
|
return new
|
|
|
|
# We could do these, not sure about it
|
|
"""
|
|
def _eval_evalf(self, prec=None):
|
|
return Float('inf')
|
|
|
|
def evalf(self, prec=None, **options):
|
|
return self._eval_evalf(prec)
|
|
"""
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __add__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other in (S.Infinity, S.NegativeInfinity):
|
|
return other
|
|
if other in (S.NegativeIntInfinity, S.NaN):
|
|
return S.NaN
|
|
return self
|
|
return Number.__add__(self, other)
|
|
|
|
__radd__ = __add__
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __sub__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other is S.Infinity:
|
|
return S.NegativeInfinity
|
|
if other is S.NegativeInfinity:
|
|
return S.Infinity
|
|
if other in (S.IntInfinity, S.NaN):
|
|
return S.NaN
|
|
return self
|
|
return Number.__sub__(self, other)
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __rsub__(self, other):
|
|
return (-self).__add__(other)
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __mul__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other.is_zero or other is S.NaN:
|
|
return S.NaN
|
|
if other.is_extended_positive:
|
|
return self
|
|
return S.NegativeIntInfinity
|
|
return Number.__mul__(self, other)
|
|
|
|
__rmul__ = __mul__
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __truediv__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other in (
|
|
S.Infinity,
|
|
S.IntInfinity,
|
|
S.NegativeInfinity,
|
|
S.NegativeIntInfinity,
|
|
S.NaN,
|
|
):
|
|
return S.NaN
|
|
if other.is_extended_nonnegative:
|
|
return S.Infinity # truediv produces float
|
|
return S.NegativeInfinity # truediv produces float
|
|
return Number.__truediv__(self, other)
|
|
|
|
def __abs__(self):
|
|
return S.IntInfinity
|
|
|
|
def __neg__(self):
|
|
return S.NegativeIntInfinity
|
|
|
|
def _eval_power(self, expt):
|
|
if expt.is_extended_positive:
|
|
return S.IntInfinity
|
|
if expt.is_extended_negative:
|
|
return S.Zero
|
|
if expt is S.NaN:
|
|
return S.NaN
|
|
if expt is S.ComplexInfinity:
|
|
return S.NaN
|
|
if expt.is_extended_real is False and expt.is_number:
|
|
from sympy.functions.elementary.complexes import re
|
|
|
|
expt_real = re(expt)
|
|
if expt_real.is_positive:
|
|
return S.ComplexInfinity
|
|
if expt_real.is_negative:
|
|
return S.Zero
|
|
if expt_real.is_zero:
|
|
return S.NaN
|
|
|
|
return self ** expt.evalf()
|
|
|
|
def _as_mpf_val(self, prec):
|
|
return mlib.finf
|
|
|
|
def __hash__(self):
|
|
return super().__hash__()
|
|
|
|
def __eq__(self, other):
|
|
return other is S.IntInfinity
|
|
|
|
def __ne__(self, other):
|
|
return other is not S.IntInfinity
|
|
|
|
def __gt__(self, other):
|
|
if other is S.Infinity:
|
|
return sympy.false # sympy.oo > int_oo
|
|
elif other is S.IntInfinity:
|
|
return sympy.false # consistency with sympy.oo
|
|
else:
|
|
return sympy.true
|
|
|
|
def __ge__(self, other):
|
|
if other is S.Infinity:
|
|
return sympy.false # sympy.oo > int_oo
|
|
elif other is S.IntInfinity:
|
|
return sympy.true # consistency with sympy.oo
|
|
else:
|
|
return sympy.true
|
|
|
|
def __lt__(self, other):
|
|
if other is S.Infinity:
|
|
return sympy.true # sympy.oo > int_oo
|
|
elif other is S.IntInfinity:
|
|
return sympy.false # consistency with sympy.oo
|
|
else:
|
|
return sympy.false
|
|
|
|
def __le__(self, other):
|
|
if other is S.Infinity:
|
|
return sympy.true # sympy.oo > int_oo
|
|
elif other is S.IntInfinity:
|
|
return sympy.true # consistency with sympy.oo
|
|
else:
|
|
return sympy.false
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __mod__(self, other):
|
|
if not isinstance(other, Expr):
|
|
return NotImplemented
|
|
return S.NaN
|
|
|
|
__rmod__ = __mod__
|
|
|
|
def floor(self):
|
|
return self
|
|
|
|
def ceiling(self):
|
|
return self
|
|
|
|
|
|
int_oo = S.IntInfinity
|
|
|
|
|
|
class NegativeIntInfinity(Number, metaclass=Singleton):
|
|
"""Negative integer infinite quantity.
|
|
|
|
NegativeInfinity is a singleton, and can be accessed
|
|
by ``S.NegativeInfinity``.
|
|
|
|
See Also
|
|
========
|
|
|
|
IntInfinity
|
|
"""
|
|
|
|
# Ensure we get dispatched to before plain numbers
|
|
_op_priority = 100.0
|
|
|
|
is_integer = True
|
|
is_extended_real = True
|
|
is_commutative = True
|
|
is_comparable = True
|
|
is_extended_negative = True
|
|
is_number = True
|
|
is_prime = False
|
|
|
|
__slots__ = ()
|
|
|
|
def __new__(cls):
|
|
return AtomicExpr.__new__(cls)
|
|
|
|
def _eval_subs(self, old, new):
|
|
if self == old:
|
|
return new
|
|
|
|
def _sympystr(self, printer):
|
|
return "-int_oo"
|
|
|
|
"""
|
|
def _eval_evalf(self, prec=None):
|
|
return Float('-inf')
|
|
|
|
def evalf(self, prec=None, **options):
|
|
return self._eval_evalf(prec)
|
|
"""
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __add__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other is S.Infinity:
|
|
return S.Infinity
|
|
if other in (S.IntInfinity, S.NaN):
|
|
return S.NaN
|
|
return self
|
|
return Number.__add__(self, other)
|
|
|
|
__radd__ = __add__
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __sub__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other is S.NegativeInfinity:
|
|
return S.Infinity
|
|
if other in (S.NegativeIntInfinity, S.NaN):
|
|
return S.NaN
|
|
return self
|
|
return Number.__sub__(self, other)
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __rsub__(self, other):
|
|
return (-self).__add__(other)
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __mul__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other.is_zero or other is S.NaN:
|
|
return S.NaN
|
|
if other.is_extended_positive:
|
|
return self
|
|
return S.IntInfinity
|
|
return Number.__mul__(self, other)
|
|
|
|
__rmul__ = __mul__
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __truediv__(self, other):
|
|
if isinstance(other, Number) and global_parameters.evaluate:
|
|
if other in (
|
|
S.Infinity,
|
|
S.IntInfinity,
|
|
S.NegativeInfinity,
|
|
S.NegativeIntInfinity,
|
|
S.NaN,
|
|
):
|
|
return S.NaN
|
|
if other.is_extended_nonnegative:
|
|
return self
|
|
return S.Infinity # truediv returns float
|
|
return Number.__truediv__(self, other)
|
|
|
|
def __abs__(self):
|
|
return S.IntInfinity
|
|
|
|
def __neg__(self):
|
|
return S.IntInfinity
|
|
|
|
def _eval_power(self, expt):
|
|
if expt.is_number:
|
|
if expt in (
|
|
S.NaN,
|
|
S.Infinity,
|
|
S.NegativeInfinity,
|
|
S.IntInfinity,
|
|
S.NegativeIntInfinity,
|
|
):
|
|
return S.NaN
|
|
|
|
if isinstance(expt, sympy.Integer) and expt.is_extended_positive:
|
|
if expt.is_odd:
|
|
return S.NegativeIntInfinity
|
|
else:
|
|
return S.IntInfinity
|
|
|
|
inf_part = S.IntInfinity**expt
|
|
s_part = S.NegativeOne**expt
|
|
if inf_part == 0 and s_part.is_finite:
|
|
return inf_part
|
|
if (
|
|
inf_part is S.ComplexInfinity
|
|
and s_part.is_finite
|
|
and not s_part.is_zero
|
|
):
|
|
return S.ComplexInfinity
|
|
return s_part * inf_part
|
|
|
|
def _as_mpf_val(self, prec):
|
|
return mlib.fninf
|
|
|
|
def __hash__(self):
|
|
return super().__hash__()
|
|
|
|
def __eq__(self, other):
|
|
return other is S.NegativeIntInfinity
|
|
|
|
def __ne__(self, other):
|
|
return other is not S.NegativeIntInfinity
|
|
|
|
def __gt__(self, other):
|
|
if other is S.NegativeInfinity:
|
|
return sympy.true # -sympy.oo < -int_oo
|
|
elif other is S.NegativeIntInfinity:
|
|
return sympy.false # consistency with sympy.oo
|
|
else:
|
|
return sympy.false
|
|
|
|
def __ge__(self, other):
|
|
if other is S.NegativeInfinity:
|
|
return sympy.true # -sympy.oo < -int_oo
|
|
elif other is S.NegativeIntInfinity:
|
|
return sympy.true # consistency with sympy.oo
|
|
else:
|
|
return sympy.false
|
|
|
|
def __lt__(self, other):
|
|
if other is S.NegativeInfinity:
|
|
return sympy.false # -sympy.oo < -int_oo
|
|
elif other is S.NegativeIntInfinity:
|
|
return sympy.false # consistency with sympy.oo
|
|
else:
|
|
return sympy.true
|
|
|
|
def __le__(self, other):
|
|
if other is S.NegativeInfinity:
|
|
return sympy.false # -sympy.oo < -int_oo
|
|
elif other is S.NegativeIntInfinity:
|
|
return sympy.true # consistency with sympy.oo
|
|
else:
|
|
return sympy.true
|
|
|
|
@_sympifyit("other", NotImplemented)
|
|
def __mod__(self, other):
|
|
if not isinstance(other, Expr):
|
|
return NotImplemented
|
|
return S.NaN
|
|
|
|
__rmod__ = __mod__
|
|
|
|
def floor(self):
|
|
return self
|
|
|
|
def ceiling(self):
|
|
return self
|
|
|
|
def as_powers_dict(self):
|
|
return {S.NegativeOne: 1, S.IntInfinity: 1}
|