integers.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. from typing import Tuple as tTuple
  2. from sympy.core.basic import Basic
  3. from sympy.core.expr import Expr
  4. from sympy.core import Add, S
  5. from sympy.core.evalf import get_integer_part, PrecisionExhausted
  6. from sympy.core.function import Function
  7. from sympy.core.logic import fuzzy_or
  8. from sympy.core.numbers import Integer
  9. from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq
  10. from sympy.core.symbol import Symbol
  11. from sympy.core.sympify import _sympify
  12. from sympy.multipledispatch import dispatch
  13. ###############################################################################
  14. ######################### FLOOR and CEILING FUNCTIONS #########################
  15. ###############################################################################
  16. class RoundFunction(Function):
  17. """Abstract base class for rounding functions."""
  18. args: tTuple[Expr]
  19. @classmethod
  20. def eval(cls, arg):
  21. from sympy.functions.elementary.complexes import im
  22. v = cls._eval_number(arg)
  23. if v is not None:
  24. return v
  25. if arg.is_integer or arg.is_finite is False:
  26. return arg
  27. if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
  28. i = im(arg)
  29. if not i.has(S.ImaginaryUnit):
  30. return cls(i)*S.ImaginaryUnit
  31. return cls(arg, evaluate=False)
  32. # Integral, numerical, symbolic part
  33. ipart = npart = spart = S.Zero
  34. # Extract integral (or complex integral) terms
  35. terms = Add.make_args(arg)
  36. for t in terms:
  37. if t.is_integer or (t.is_imaginary and im(t).is_integer):
  38. ipart += t
  39. elif t.has(Symbol):
  40. spart += t
  41. else:
  42. npart += t
  43. if not (npart or spart):
  44. return ipart
  45. # Evaluate npart numerically if independent of spart
  46. if npart and (
  47. not spart or
  48. npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or
  49. npart.is_imaginary and spart.is_real):
  50. try:
  51. r, i = get_integer_part(
  52. npart, cls._dir, {}, return_ints=True)
  53. ipart += Integer(r) + Integer(i)*S.ImaginaryUnit
  54. npart = S.Zero
  55. except (PrecisionExhausted, NotImplementedError):
  56. pass
  57. spart += npart
  58. if not spart:
  59. return ipart
  60. elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real:
  61. return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit
  62. elif isinstance(spart, (floor, ceiling)):
  63. return ipart + spart
  64. else:
  65. return ipart + cls(spart, evaluate=False)
  66. @classmethod
  67. def _eval_number(cls, arg):
  68. raise NotImplementedError()
  69. def _eval_is_finite(self):
  70. return self.args[0].is_finite
  71. def _eval_is_real(self):
  72. return self.args[0].is_real
  73. def _eval_is_integer(self):
  74. return self.args[0].is_real
  75. class floor(RoundFunction):
  76. """
  77. Floor is a univariate function which returns the largest integer
  78. value not greater than its argument. This implementation
  79. generalizes floor to complex numbers by taking the floor of the
  80. real and imaginary parts separately.
  81. Examples
  82. ========
  83. >>> from sympy import floor, E, I, S, Float, Rational
  84. >>> floor(17)
  85. 17
  86. >>> floor(Rational(23, 10))
  87. 2
  88. >>> floor(2*E)
  89. 5
  90. >>> floor(-Float(0.567))
  91. -1
  92. >>> floor(-I/2)
  93. -I
  94. >>> floor(S(5)/2 + 5*I/2)
  95. 2 + 2*I
  96. See Also
  97. ========
  98. sympy.functions.elementary.integers.ceiling
  99. References
  100. ==========
  101. .. [1] "Concrete mathematics" by Graham, pp. 87
  102. .. [2] http://mathworld.wolfram.com/FloorFunction.html
  103. """
  104. _dir = -1
  105. @classmethod
  106. def _eval_number(cls, arg):
  107. if arg.is_Number:
  108. return arg.floor()
  109. elif any(isinstance(i, j)
  110. for i in (arg, -arg) for j in (floor, ceiling)):
  111. return arg
  112. if arg.is_NumberSymbol:
  113. return arg.approximation_interval(Integer)[0]
  114. def _eval_as_leading_term(self, x, logx=None, cdir=0):
  115. arg = self.args[0]
  116. arg0 = arg.subs(x, 0)
  117. r = self.subs(x, 0)
  118. if arg0.is_finite:
  119. if arg0 == r:
  120. if cdir == 0:
  121. ndirl = arg.dir(x, cdir=-1)
  122. ndir = arg.dir(x, cdir=1)
  123. if ndir != ndirl:
  124. raise ValueError("Two sided limit of %s around 0"
  125. "does not exist" % self)
  126. else:
  127. ndir = arg.dir(x, cdir=cdir)
  128. return r - 1 if ndir.is_negative else r
  129. else:
  130. return r
  131. return arg.as_leading_term(x, logx=logx, cdir=cdir)
  132. def _eval_nseries(self, x, n, logx, cdir=0):
  133. arg = self.args[0]
  134. arg0 = arg.subs(x, 0)
  135. if arg0.is_infinite:
  136. from sympy.calculus.accumulationbounds import AccumBounds
  137. from sympy.series.order import Order
  138. s = arg._eval_nseries(x, n, logx, cdir)
  139. o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0)
  140. return s + o
  141. r = self.subs(x, 0)
  142. if arg0 == r:
  143. ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
  144. return r - 1 if ndir.is_negative else r
  145. else:
  146. return r
  147. def _eval_is_negative(self):
  148. return self.args[0].is_negative
  149. def _eval_is_nonnegative(self):
  150. return self.args[0].is_nonnegative
  151. def _eval_rewrite_as_ceiling(self, arg, **kwargs):
  152. return -ceiling(-arg)
  153. def _eval_rewrite_as_frac(self, arg, **kwargs):
  154. return arg - frac(arg)
  155. def __le__(self, other):
  156. other = S(other)
  157. if self.args[0].is_real:
  158. if other.is_integer:
  159. return self.args[0] < other + 1
  160. if other.is_number and other.is_real:
  161. return self.args[0] < ceiling(other)
  162. if self.args[0] == other and other.is_real:
  163. return S.true
  164. if other is S.Infinity and self.is_finite:
  165. return S.true
  166. return Le(self, other, evaluate=False)
  167. def __ge__(self, other):
  168. other = S(other)
  169. if self.args[0].is_real:
  170. if other.is_integer:
  171. return self.args[0] >= other
  172. if other.is_number and other.is_real:
  173. return self.args[0] >= ceiling(other)
  174. if self.args[0] == other and other.is_real:
  175. return S.false
  176. if other is S.NegativeInfinity and self.is_finite:
  177. return S.true
  178. return Ge(self, other, evaluate=False)
  179. def __gt__(self, other):
  180. other = S(other)
  181. if self.args[0].is_real:
  182. if other.is_integer:
  183. return self.args[0] >= other + 1
  184. if other.is_number and other.is_real:
  185. return self.args[0] >= ceiling(other)
  186. if self.args[0] == other and other.is_real:
  187. return S.false
  188. if other is S.NegativeInfinity and self.is_finite:
  189. return S.true
  190. return Gt(self, other, evaluate=False)
  191. def __lt__(self, other):
  192. other = S(other)
  193. if self.args[0].is_real:
  194. if other.is_integer:
  195. return self.args[0] < other
  196. if other.is_number and other.is_real:
  197. return self.args[0] < ceiling(other)
  198. if self.args[0] == other and other.is_real:
  199. return S.false
  200. if other is S.Infinity and self.is_finite:
  201. return S.true
  202. return Lt(self, other, evaluate=False)
  203. @dispatch(floor, Expr)
  204. def _eval_is_eq(lhs, rhs): # noqa:F811
  205. return is_eq(lhs.rewrite(ceiling), rhs) or \
  206. is_eq(lhs.rewrite(frac),rhs)
  207. class ceiling(RoundFunction):
  208. """
  209. Ceiling is a univariate function which returns the smallest integer
  210. value not less than its argument. This implementation
  211. generalizes ceiling to complex numbers by taking the ceiling of the
  212. real and imaginary parts separately.
  213. Examples
  214. ========
  215. >>> from sympy import ceiling, E, I, S, Float, Rational
  216. >>> ceiling(17)
  217. 17
  218. >>> ceiling(Rational(23, 10))
  219. 3
  220. >>> ceiling(2*E)
  221. 6
  222. >>> ceiling(-Float(0.567))
  223. 0
  224. >>> ceiling(I/2)
  225. I
  226. >>> ceiling(S(5)/2 + 5*I/2)
  227. 3 + 3*I
  228. See Also
  229. ========
  230. sympy.functions.elementary.integers.floor
  231. References
  232. ==========
  233. .. [1] "Concrete mathematics" by Graham, pp. 87
  234. .. [2] http://mathworld.wolfram.com/CeilingFunction.html
  235. """
  236. _dir = 1
  237. @classmethod
  238. def _eval_number(cls, arg):
  239. if arg.is_Number:
  240. return arg.ceiling()
  241. elif any(isinstance(i, j)
  242. for i in (arg, -arg) for j in (floor, ceiling)):
  243. return arg
  244. if arg.is_NumberSymbol:
  245. return arg.approximation_interval(Integer)[1]
  246. def _eval_as_leading_term(self, x, logx=None, cdir=0):
  247. arg = self.args[0]
  248. arg0 = arg.subs(x, 0)
  249. r = self.subs(x, 0)
  250. if arg0.is_finite:
  251. if arg0 == r:
  252. if cdir == 0:
  253. ndirl = arg.dir(x, cdir=-1)
  254. ndir = arg.dir(x, cdir=1)
  255. if ndir != ndirl:
  256. raise ValueError("Two sided limit of %s around 0"
  257. "does not exist" % self)
  258. else:
  259. ndir = arg.dir(x, cdir=cdir)
  260. return r if ndir.is_negative else r + 1
  261. else:
  262. return r
  263. return arg.as_leading_term(x, logx=logx, cdir=cdir)
  264. def _eval_nseries(self, x, n, logx, cdir=0):
  265. arg = self.args[0]
  266. arg0 = arg.subs(x, 0)
  267. if arg0.is_infinite:
  268. from sympy.calculus.accumulationbounds import AccumBounds
  269. from sympy.series.order import Order
  270. s = arg._eval_nseries(x, n, logx, cdir)
  271. o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1)
  272. return s + o
  273. r = self.subs(x, 0)
  274. if arg0 == r:
  275. ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1)
  276. return r if ndir.is_negative else r + 1
  277. else:
  278. return r
  279. def _eval_rewrite_as_floor(self, arg, **kwargs):
  280. return -floor(-arg)
  281. def _eval_rewrite_as_frac(self, arg, **kwargs):
  282. return arg + frac(-arg)
  283. def _eval_is_positive(self):
  284. return self.args[0].is_positive
  285. def _eval_is_nonpositive(self):
  286. return self.args[0].is_nonpositive
  287. def __lt__(self, other):
  288. other = S(other)
  289. if self.args[0].is_real:
  290. if other.is_integer:
  291. return self.args[0] <= other - 1
  292. if other.is_number and other.is_real:
  293. return self.args[0] <= floor(other)
  294. if self.args[0] == other and other.is_real:
  295. return S.false
  296. if other is S.Infinity and self.is_finite:
  297. return S.true
  298. return Lt(self, other, evaluate=False)
  299. def __gt__(self, other):
  300. other = S(other)
  301. if self.args[0].is_real:
  302. if other.is_integer:
  303. return self.args[0] > other
  304. if other.is_number and other.is_real:
  305. return self.args[0] > floor(other)
  306. if self.args[0] == other and other.is_real:
  307. return S.false
  308. if other is S.NegativeInfinity and self.is_finite:
  309. return S.true
  310. return Gt(self, other, evaluate=False)
  311. def __ge__(self, other):
  312. other = S(other)
  313. if self.args[0].is_real:
  314. if other.is_integer:
  315. return self.args[0] > other - 1
  316. if other.is_number and other.is_real:
  317. return self.args[0] > floor(other)
  318. if self.args[0] == other and other.is_real:
  319. return S.true
  320. if other is S.NegativeInfinity and self.is_finite:
  321. return S.true
  322. return Ge(self, other, evaluate=False)
  323. def __le__(self, other):
  324. other = S(other)
  325. if self.args[0].is_real:
  326. if other.is_integer:
  327. return self.args[0] <= other
  328. if other.is_number and other.is_real:
  329. return self.args[0] <= floor(other)
  330. if self.args[0] == other and other.is_real:
  331. return S.false
  332. if other is S.Infinity and self.is_finite:
  333. return S.true
  334. return Le(self, other, evaluate=False)
  335. @dispatch(ceiling, Basic) # type:ignore
  336. def _eval_is_eq(lhs, rhs): # noqa:F811
  337. return is_eq(lhs.rewrite(floor), rhs) or is_eq(lhs.rewrite(frac),rhs)
  338. class frac(Function):
  339. r"""Represents the fractional part of x
  340. For real numbers it is defined [1]_ as
  341. .. math::
  342. x - \left\lfloor{x}\right\rfloor
  343. Examples
  344. ========
  345. >>> from sympy import Symbol, frac, Rational, floor, I
  346. >>> frac(Rational(4, 3))
  347. 1/3
  348. >>> frac(-Rational(4, 3))
  349. 2/3
  350. returns zero for integer arguments
  351. >>> n = Symbol('n', integer=True)
  352. >>> frac(n)
  353. 0
  354. rewrite as floor
  355. >>> x = Symbol('x')
  356. >>> frac(x).rewrite(floor)
  357. x - floor(x)
  358. for complex arguments
  359. >>> r = Symbol('r', real=True)
  360. >>> t = Symbol('t', real=True)
  361. >>> frac(t + I*r)
  362. I*frac(r) + frac(t)
  363. See Also
  364. ========
  365. sympy.functions.elementary.integers.floor
  366. sympy.functions.elementary.integers.ceiling
  367. References
  368. ===========
  369. .. [1] https://en.wikipedia.org/wiki/Fractional_part
  370. .. [2] http://mathworld.wolfram.com/FractionalPart.html
  371. """
  372. @classmethod
  373. def eval(cls, arg):
  374. from sympy.calculus.accumulationbounds import AccumBounds
  375. from sympy.functions.elementary.complexes import im
  376. def _eval(arg):
  377. if arg in (S.Infinity, S.NegativeInfinity):
  378. return AccumBounds(0, 1)
  379. if arg.is_integer:
  380. return S.Zero
  381. if arg.is_number:
  382. if arg is S.NaN:
  383. return S.NaN
  384. elif arg is S.ComplexInfinity:
  385. return S.NaN
  386. else:
  387. return arg - floor(arg)
  388. return cls(arg, evaluate=False)
  389. terms = Add.make_args(arg)
  390. real, imag = S.Zero, S.Zero
  391. for t in terms:
  392. # Two checks are needed for complex arguments
  393. # see issue-7649 for details
  394. if t.is_imaginary or (S.ImaginaryUnit*t).is_real:
  395. i = im(t)
  396. if not i.has(S.ImaginaryUnit):
  397. imag += i
  398. else:
  399. real += t
  400. else:
  401. real += t
  402. real = _eval(real)
  403. imag = _eval(imag)
  404. return real + S.ImaginaryUnit*imag
  405. def _eval_rewrite_as_floor(self, arg, **kwargs):
  406. return arg - floor(arg)
  407. def _eval_rewrite_as_ceiling(self, arg, **kwargs):
  408. return arg + ceiling(-arg)
  409. def _eval_is_finite(self):
  410. return True
  411. def _eval_is_real(self):
  412. return self.args[0].is_extended_real
  413. def _eval_is_imaginary(self):
  414. return self.args[0].is_imaginary
  415. def _eval_is_integer(self):
  416. return self.args[0].is_integer
  417. def _eval_is_zero(self):
  418. return fuzzy_or([self.args[0].is_zero, self.args[0].is_integer])
  419. def _eval_is_negative(self):
  420. return False
  421. def __ge__(self, other):
  422. if self.is_extended_real:
  423. other = _sympify(other)
  424. # Check if other <= 0
  425. if other.is_extended_nonpositive:
  426. return S.true
  427. # Check if other >= 1
  428. res = self._value_one_or_more(other)
  429. if res is not None:
  430. return not(res)
  431. return Ge(self, other, evaluate=False)
  432. def __gt__(self, other):
  433. if self.is_extended_real:
  434. other = _sympify(other)
  435. # Check if other < 0
  436. res = self._value_one_or_more(other)
  437. if res is not None:
  438. return not(res)
  439. # Check if other >= 1
  440. if other.is_extended_negative:
  441. return S.true
  442. return Gt(self, other, evaluate=False)
  443. def __le__(self, other):
  444. if self.is_extended_real:
  445. other = _sympify(other)
  446. # Check if other < 0
  447. if other.is_extended_negative:
  448. return S.false
  449. # Check if other >= 1
  450. res = self._value_one_or_more(other)
  451. if res is not None:
  452. return res
  453. return Le(self, other, evaluate=False)
  454. def __lt__(self, other):
  455. if self.is_extended_real:
  456. other = _sympify(other)
  457. # Check if other <= 0
  458. if other.is_extended_nonpositive:
  459. return S.false
  460. # Check if other >= 1
  461. res = self._value_one_or_more(other)
  462. if res is not None:
  463. return res
  464. return Lt(self, other, evaluate=False)
  465. def _value_one_or_more(self, other):
  466. if other.is_extended_real:
  467. if other.is_number:
  468. res = other >= 1
  469. if res and not isinstance(res, Relational):
  470. return S.true
  471. if other.is_integer and other.is_positive:
  472. return S.true
  473. @dispatch(frac, Basic) # type:ignore
  474. def _eval_is_eq(lhs, rhs): # noqa:F811
  475. if (lhs.rewrite(floor) == rhs) or \
  476. (lhs.rewrite(ceiling) == rhs):
  477. return True
  478. # Check if other < 0
  479. if rhs.is_extended_negative:
  480. return False
  481. # Check if other >= 1
  482. res = lhs._value_one_or_more(rhs)
  483. if res is not None:
  484. return False