numbers.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. # mypy: allow-untyped-defs
  2. import mpmath.libmp as mlib # type: ignore[import-untyped]
  3. import sympy
  4. from sympy import Expr
  5. from sympy.core.decorators import _sympifyit
  6. from sympy.core.expr import AtomicExpr
  7. from sympy.core.numbers import Number
  8. from sympy.core.parameters import global_parameters
  9. from sympy.core.singleton import S, Singleton
  10. class IntInfinity(Number, metaclass=Singleton):
  11. r"""Positive integer infinite quantity.
  12. Integer infinity is a value in an extended integers which
  13. is greater than all other integers. We distinguish it from
  14. sympy's existing notion of infinity in that it reports that
  15. it is_integer.
  16. Infinity is a singleton, and can be accessed by ``S.IntInfinity``,
  17. or can be imported as ``int_oo``.
  18. """
  19. # NB: We can't actually mark this as infinite, as integer and infinite are
  20. # inconsistent assumptions in sympy. We also report that we are complex,
  21. # different from sympy.oo
  22. is_integer = True
  23. is_commutative = True
  24. is_number = True
  25. is_extended_real = True
  26. is_comparable = True
  27. is_extended_positive = True
  28. is_prime = False
  29. # Ensure we get dispatched to before plain numbers
  30. _op_priority = 100.0
  31. __slots__ = ()
  32. def __new__(cls):
  33. return AtomicExpr.__new__(cls)
  34. def _sympystr(self, printer):
  35. return "int_oo"
  36. def _eval_subs(self, old, new):
  37. if self == old:
  38. return new
  39. # We could do these, not sure about it
  40. """
  41. def _eval_evalf(self, prec=None):
  42. return Float('inf')
  43. def evalf(self, prec=None, **options):
  44. return self._eval_evalf(prec)
  45. """
  46. @_sympifyit("other", NotImplemented)
  47. def __add__(self, other):
  48. if isinstance(other, Number) and global_parameters.evaluate:
  49. if other in (S.Infinity, S.NegativeInfinity):
  50. return other
  51. if other in (S.NegativeIntInfinity, S.NaN):
  52. return S.NaN
  53. return self
  54. return Number.__add__(self, other)
  55. __radd__ = __add__
  56. @_sympifyit("other", NotImplemented)
  57. def __sub__(self, other):
  58. if isinstance(other, Number) and global_parameters.evaluate:
  59. if other is S.Infinity:
  60. return S.NegativeInfinity
  61. if other is S.NegativeInfinity:
  62. return S.Infinity
  63. if other in (S.IntInfinity, S.NaN):
  64. return S.NaN
  65. return self
  66. return Number.__sub__(self, other)
  67. @_sympifyit("other", NotImplemented)
  68. def __rsub__(self, other):
  69. return (-self).__add__(other)
  70. @_sympifyit("other", NotImplemented)
  71. def __mul__(self, other):
  72. if isinstance(other, Number) and global_parameters.evaluate:
  73. if other.is_zero or other is S.NaN:
  74. return S.NaN
  75. if other.is_extended_positive:
  76. return self
  77. return S.NegativeIntInfinity
  78. return Number.__mul__(self, other)
  79. __rmul__ = __mul__
  80. @_sympifyit("other", NotImplemented)
  81. def __truediv__(self, other):
  82. if isinstance(other, Number) and global_parameters.evaluate:
  83. if other in (
  84. S.Infinity,
  85. S.IntInfinity,
  86. S.NegativeInfinity,
  87. S.NegativeIntInfinity,
  88. S.NaN,
  89. ):
  90. return S.NaN
  91. if other.is_extended_nonnegative:
  92. return S.Infinity # truediv produces float
  93. return S.NegativeInfinity # truediv produces float
  94. return Number.__truediv__(self, other)
  95. def __abs__(self):
  96. return S.IntInfinity
  97. def __neg__(self):
  98. return S.NegativeIntInfinity
  99. def _eval_power(self, expt):
  100. if expt.is_extended_positive:
  101. return S.IntInfinity
  102. if expt.is_extended_negative:
  103. return S.Zero
  104. if expt is S.NaN:
  105. return S.NaN
  106. if expt is S.ComplexInfinity:
  107. return S.NaN
  108. if expt.is_extended_real is False and expt.is_number:
  109. from sympy.functions.elementary.complexes import re
  110. expt_real = re(expt)
  111. if expt_real.is_positive:
  112. return S.ComplexInfinity
  113. if expt_real.is_negative:
  114. return S.Zero
  115. if expt_real.is_zero:
  116. return S.NaN
  117. return self ** expt.evalf()
  118. def _as_mpf_val(self, prec):
  119. return mlib.finf
  120. def __hash__(self):
  121. return super().__hash__()
  122. def __eq__(self, other):
  123. return other is S.IntInfinity
  124. def __ne__(self, other):
  125. return other is not S.IntInfinity
  126. def __gt__(self, other):
  127. if other is S.Infinity:
  128. return sympy.false # sympy.oo > int_oo
  129. elif other is S.IntInfinity:
  130. return sympy.false # consistency with sympy.oo
  131. else:
  132. return sympy.true
  133. def __ge__(self, other):
  134. if other is S.Infinity:
  135. return sympy.false # sympy.oo > int_oo
  136. elif other is S.IntInfinity:
  137. return sympy.true # consistency with sympy.oo
  138. else:
  139. return sympy.true
  140. def __lt__(self, other):
  141. if other is S.Infinity:
  142. return sympy.true # sympy.oo > int_oo
  143. elif other is S.IntInfinity:
  144. return sympy.false # consistency with sympy.oo
  145. else:
  146. return sympy.false
  147. def __le__(self, other):
  148. if other is S.Infinity:
  149. return sympy.true # sympy.oo > int_oo
  150. elif other is S.IntInfinity:
  151. return sympy.true # consistency with sympy.oo
  152. else:
  153. return sympy.false
  154. @_sympifyit("other", NotImplemented)
  155. def __mod__(self, other):
  156. if not isinstance(other, Expr):
  157. return NotImplemented
  158. return S.NaN
  159. __rmod__ = __mod__
  160. def floor(self):
  161. return self
  162. def ceiling(self):
  163. return self
  164. int_oo = S.IntInfinity
  165. class NegativeIntInfinity(Number, metaclass=Singleton):
  166. """Negative integer infinite quantity.
  167. NegativeInfinity is a singleton, and can be accessed
  168. by ``S.NegativeInfinity``.
  169. See Also
  170. ========
  171. IntInfinity
  172. """
  173. # Ensure we get dispatched to before plain numbers
  174. _op_priority = 100.0
  175. is_integer = True
  176. is_extended_real = True
  177. is_commutative = True
  178. is_comparable = True
  179. is_extended_negative = True
  180. is_number = True
  181. is_prime = False
  182. __slots__ = ()
  183. def __new__(cls):
  184. return AtomicExpr.__new__(cls)
  185. def _eval_subs(self, old, new):
  186. if self == old:
  187. return new
  188. def _sympystr(self, printer):
  189. return "-int_oo"
  190. """
  191. def _eval_evalf(self, prec=None):
  192. return Float('-inf')
  193. def evalf(self, prec=None, **options):
  194. return self._eval_evalf(prec)
  195. """
  196. @_sympifyit("other", NotImplemented)
  197. def __add__(self, other):
  198. if isinstance(other, Number) and global_parameters.evaluate:
  199. if other is S.Infinity:
  200. return S.Infinity
  201. if other in (S.IntInfinity, S.NaN):
  202. return S.NaN
  203. return self
  204. return Number.__add__(self, other)
  205. __radd__ = __add__
  206. @_sympifyit("other", NotImplemented)
  207. def __sub__(self, other):
  208. if isinstance(other, Number) and global_parameters.evaluate:
  209. if other is S.NegativeInfinity:
  210. return S.Infinity
  211. if other in (S.NegativeIntInfinity, S.NaN):
  212. return S.NaN
  213. return self
  214. return Number.__sub__(self, other)
  215. @_sympifyit("other", NotImplemented)
  216. def __rsub__(self, other):
  217. return (-self).__add__(other)
  218. @_sympifyit("other", NotImplemented)
  219. def __mul__(self, other):
  220. if isinstance(other, Number) and global_parameters.evaluate:
  221. if other.is_zero or other is S.NaN:
  222. return S.NaN
  223. if other.is_extended_positive:
  224. return self
  225. return S.IntInfinity
  226. return Number.__mul__(self, other)
  227. __rmul__ = __mul__
  228. @_sympifyit("other", NotImplemented)
  229. def __truediv__(self, other):
  230. if isinstance(other, Number) and global_parameters.evaluate:
  231. if other in (
  232. S.Infinity,
  233. S.IntInfinity,
  234. S.NegativeInfinity,
  235. S.NegativeIntInfinity,
  236. S.NaN,
  237. ):
  238. return S.NaN
  239. if other.is_extended_nonnegative:
  240. return self
  241. return S.Infinity # truediv returns float
  242. return Number.__truediv__(self, other)
  243. def __abs__(self):
  244. return S.IntInfinity
  245. def __neg__(self):
  246. return S.IntInfinity
  247. def _eval_power(self, expt):
  248. if expt.is_number:
  249. if expt in (
  250. S.NaN,
  251. S.Infinity,
  252. S.NegativeInfinity,
  253. S.IntInfinity,
  254. S.NegativeIntInfinity,
  255. ):
  256. return S.NaN
  257. if isinstance(expt, sympy.Integer) and expt.is_extended_positive:
  258. if expt.is_odd:
  259. return S.NegativeIntInfinity
  260. else:
  261. return S.IntInfinity
  262. inf_part = S.IntInfinity**expt
  263. s_part = S.NegativeOne**expt
  264. if inf_part == 0 and s_part.is_finite:
  265. return inf_part
  266. if (
  267. inf_part is S.ComplexInfinity
  268. and s_part.is_finite
  269. and not s_part.is_zero
  270. ):
  271. return S.ComplexInfinity
  272. return s_part * inf_part
  273. def _as_mpf_val(self, prec):
  274. return mlib.fninf
  275. def __hash__(self):
  276. return super().__hash__()
  277. def __eq__(self, other):
  278. return other is S.NegativeIntInfinity
  279. def __ne__(self, other):
  280. return other is not S.NegativeIntInfinity
  281. def __gt__(self, other):
  282. if other is S.NegativeInfinity:
  283. return sympy.true # -sympy.oo < -int_oo
  284. elif other is S.NegativeIntInfinity:
  285. return sympy.false # consistency with sympy.oo
  286. else:
  287. return sympy.false
  288. def __ge__(self, other):
  289. if other is S.NegativeInfinity:
  290. return sympy.true # -sympy.oo < -int_oo
  291. elif other is S.NegativeIntInfinity:
  292. return sympy.true # consistency with sympy.oo
  293. else:
  294. return sympy.false
  295. def __lt__(self, other):
  296. if other is S.NegativeInfinity:
  297. return sympy.false # -sympy.oo < -int_oo
  298. elif other is S.NegativeIntInfinity:
  299. return sympy.false # consistency with sympy.oo
  300. else:
  301. return sympy.true
  302. def __le__(self, other):
  303. if other is S.NegativeInfinity:
  304. return sympy.false # -sympy.oo < -int_oo
  305. elif other is S.NegativeIntInfinity:
  306. return sympy.true # consistency with sympy.oo
  307. else:
  308. return sympy.true
  309. @_sympifyit("other", NotImplemented)
  310. def __mod__(self, other):
  311. if not isinstance(other, Expr):
  312. return NotImplemented
  313. return S.NaN
  314. __rmod__ = __mod__
  315. def floor(self):
  316. return self
  317. def ceiling(self):
  318. return self
  319. def as_powers_dict(self):
  320. return {S.NegativeOne: 1, S.IntInfinity: 1}