m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1241 lines
35 KiB

6 months ago
  1. from sympy.core.basic import Basic
  2. from sympy.core.cache import cacheit
  3. from sympy.core.containers import Tuple
  4. from sympy.core.decorators import call_highest_priority
  5. from sympy.core.parameters import global_parameters
  6. from sympy.core.function import AppliedUndef
  7. from sympy.core.mul import Mul
  8. from sympy.core.numbers import Integer
  9. from sympy.core.relational import Eq
  10. from sympy.core.singleton import S, Singleton
  11. from sympy.core.sorting import ordered
  12. from sympy.core.symbol import Dummy, Symbol, Wild
  13. from sympy.core.sympify import sympify
  14. from sympy.polys import lcm, factor
  15. from sympy.sets.sets import Interval, Intersection
  16. from sympy.simplify import simplify
  17. from sympy.tensor.indexed import Idx
  18. from sympy.utilities.iterables import flatten, is_sequence, iterable
  19. from sympy.core.function import expand
  20. ###############################################################################
  21. # SEQUENCES #
  22. ###############################################################################
  23. class SeqBase(Basic):
  24. """Base class for sequences"""
  25. is_commutative = True
  26. _op_priority = 15
  27. @staticmethod
  28. def _start_key(expr):
  29. """Return start (if possible) else S.Infinity.
  30. adapted from Set._infimum_key
  31. """
  32. try:
  33. start = expr.start
  34. except (NotImplementedError,
  35. AttributeError, ValueError):
  36. start = S.Infinity
  37. return start
  38. def _intersect_interval(self, other):
  39. """Returns start and stop.
  40. Takes intersection over the two intervals.
  41. """
  42. interval = Intersection(self.interval, other.interval)
  43. return interval.inf, interval.sup
  44. @property
  45. def gen(self):
  46. """Returns the generator for the sequence"""
  47. raise NotImplementedError("(%s).gen" % self)
  48. @property
  49. def interval(self):
  50. """The interval on which the sequence is defined"""
  51. raise NotImplementedError("(%s).interval" % self)
  52. @property
  53. def start(self):
  54. """The starting point of the sequence. This point is included"""
  55. raise NotImplementedError("(%s).start" % self)
  56. @property
  57. def stop(self):
  58. """The ending point of the sequence. This point is included"""
  59. raise NotImplementedError("(%s).stop" % self)
  60. @property
  61. def length(self):
  62. """Length of the sequence"""
  63. raise NotImplementedError("(%s).length" % self)
  64. @property
  65. def variables(self):
  66. """Returns a tuple of variables that are bounded"""
  67. return ()
  68. @property
  69. def free_symbols(self):
  70. """
  71. This method returns the symbols in the object, excluding those
  72. that take on a specific value (i.e. the dummy symbols).
  73. Examples
  74. ========
  75. >>> from sympy import SeqFormula
  76. >>> from sympy.abc import n, m
  77. >>> SeqFormula(m*n**2, (n, 0, 5)).free_symbols
  78. {m}
  79. """
  80. return ({j for i in self.args for j in i.free_symbols
  81. .difference(self.variables)})
  82. @cacheit
  83. def coeff(self, pt):
  84. """Returns the coefficient at point pt"""
  85. if pt < self.start or pt > self.stop:
  86. raise IndexError("Index %s out of bounds %s" % (pt, self.interval))
  87. return self._eval_coeff(pt)
  88. def _eval_coeff(self, pt):
  89. raise NotImplementedError("The _eval_coeff method should be added to"
  90. "%s to return coefficient so it is available"
  91. "when coeff calls it."
  92. % self.func)
  93. def _ith_point(self, i):
  94. """Returns the i'th point of a sequence.
  95. Explanation
  96. ===========
  97. If start point is negative infinity, point is returned from the end.
  98. Assumes the first point to be indexed zero.
  99. Examples
  100. =========
  101. >>> from sympy import oo
  102. >>> from sympy.series.sequences import SeqPer
  103. bounded
  104. >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(0)
  105. -10
  106. >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(5)
  107. -5
  108. End is at infinity
  109. >>> SeqPer((1, 2, 3), (0, oo))._ith_point(5)
  110. 5
  111. Starts at negative infinity
  112. >>> SeqPer((1, 2, 3), (-oo, 0))._ith_point(5)
  113. -5
  114. """
  115. if self.start is S.NegativeInfinity:
  116. initial = self.stop
  117. else:
  118. initial = self.start
  119. if self.start is S.NegativeInfinity:
  120. step = -1
  121. else:
  122. step = 1
  123. return initial + i*step
  124. def _add(self, other):
  125. """
  126. Should only be used internally.
  127. Explanation
  128. ===========
  129. self._add(other) returns a new, term-wise added sequence if self
  130. knows how to add with other, otherwise it returns ``None``.
  131. ``other`` should only be a sequence object.
  132. Used within :class:`SeqAdd` class.
  133. """
  134. return None
  135. def _mul(self, other):
  136. """
  137. Should only be used internally.
  138. Explanation
  139. ===========
  140. self._mul(other) returns a new, term-wise multiplied sequence if self
  141. knows how to multiply with other, otherwise it returns ``None``.
  142. ``other`` should only be a sequence object.
  143. Used within :class:`SeqMul` class.
  144. """
  145. return None
  146. def coeff_mul(self, other):
  147. """
  148. Should be used when ``other`` is not a sequence. Should be
  149. defined to define custom behaviour.
  150. Examples
  151. ========
  152. >>> from sympy import SeqFormula
  153. >>> from sympy.abc import n
  154. >>> SeqFormula(n**2).coeff_mul(2)
  155. SeqFormula(2*n**2, (n, 0, oo))
  156. Notes
  157. =====
  158. '*' defines multiplication of sequences with sequences only.
  159. """
  160. return Mul(self, other)
  161. def __add__(self, other):
  162. """Returns the term-wise addition of 'self' and 'other'.
  163. ``other`` should be a sequence.
  164. Examples
  165. ========
  166. >>> from sympy import SeqFormula
  167. >>> from sympy.abc import n
  168. >>> SeqFormula(n**2) + SeqFormula(n**3)
  169. SeqFormula(n**3 + n**2, (n, 0, oo))
  170. """
  171. if not isinstance(other, SeqBase):
  172. raise TypeError('cannot add sequence and %s' % type(other))
  173. return SeqAdd(self, other)
  174. @call_highest_priority('__add__')
  175. def __radd__(self, other):
  176. return self + other
  177. def __sub__(self, other):
  178. """Returns the term-wise subtraction of ``self`` and ``other``.
  179. ``other`` should be a sequence.
  180. Examples
  181. ========
  182. >>> from sympy import SeqFormula
  183. >>> from sympy.abc import n
  184. >>> SeqFormula(n**2) - (SeqFormula(n))
  185. SeqFormula(n**2 - n, (n, 0, oo))
  186. """
  187. if not isinstance(other, SeqBase):
  188. raise TypeError('cannot subtract sequence and %s' % type(other))
  189. return SeqAdd(self, -other)
  190. @call_highest_priority('__sub__')
  191. def __rsub__(self, other):
  192. return (-self) + other
  193. def __neg__(self):
  194. """Negates the sequence.
  195. Examples
  196. ========
  197. >>> from sympy import SeqFormula
  198. >>> from sympy.abc import n
  199. >>> -SeqFormula(n**2)
  200. SeqFormula(-n**2, (n, 0, oo))
  201. """
  202. return self.coeff_mul(-1)
  203. def __mul__(self, other):
  204. """Returns the term-wise multiplication of 'self' and 'other'.
  205. ``other`` should be a sequence. For ``other`` not being a
  206. sequence see :func:`coeff_mul` method.
  207. Examples
  208. ========
  209. >>> from sympy import SeqFormula
  210. >>> from sympy.abc import n
  211. >>> SeqFormula(n**2) * (SeqFormula(n))
  212. SeqFormula(n**3, (n, 0, oo))
  213. """
  214. if not isinstance(other, SeqBase):
  215. raise TypeError('cannot multiply sequence and %s' % type(other))
  216. return SeqMul(self, other)
  217. @call_highest_priority('__mul__')
  218. def __rmul__(self, other):
  219. return self * other
  220. def __iter__(self):
  221. for i in range(self.length):
  222. pt = self._ith_point(i)
  223. yield self.coeff(pt)
  224. def __getitem__(self, index):
  225. if isinstance(index, int):
  226. index = self._ith_point(index)
  227. return self.coeff(index)
  228. elif isinstance(index, slice):
  229. start, stop = index.start, index.stop
  230. if start is None:
  231. start = 0
  232. if stop is None:
  233. stop = self.length
  234. return [self.coeff(self._ith_point(i)) for i in
  235. range(start, stop, index.step or 1)]
  236. def find_linear_recurrence(self,n,d=None,gfvar=None):
  237. r"""
  238. Finds the shortest linear recurrence that satisfies the first n
  239. terms of sequence of order `\leq` ``n/2`` if possible.
  240. If ``d`` is specified, find shortest linear recurrence of order
  241. `\leq` min(d, n/2) if possible.
  242. Returns list of coefficients ``[b(1), b(2), ...]`` corresponding to the
  243. recurrence relation ``x(n) = b(1)*x(n-1) + b(2)*x(n-2) + ...``
  244. Returns ``[]`` if no recurrence is found.
  245. If gfvar is specified, also returns ordinary generating function as a
  246. function of gfvar.
  247. Examples
  248. ========
  249. >>> from sympy import sequence, sqrt, oo, lucas
  250. >>> from sympy.abc import n, x, y
  251. >>> sequence(n**2).find_linear_recurrence(10, 2)
  252. []
  253. >>> sequence(n**2).find_linear_recurrence(10)
  254. [3, -3, 1]
  255. >>> sequence(2**n).find_linear_recurrence(10)
  256. [2]
  257. >>> sequence(23*n**4+91*n**2).find_linear_recurrence(10)
  258. [5, -10, 10, -5, 1]
  259. >>> sequence(sqrt(5)*(((1 + sqrt(5))/2)**n - (-(1 + sqrt(5))/2)**(-n))/5).find_linear_recurrence(10)
  260. [1, 1]
  261. >>> sequence(x+y*(-2)**(-n), (n, 0, oo)).find_linear_recurrence(30)
  262. [1/2, 1/2]
  263. >>> sequence(3*5**n + 12).find_linear_recurrence(20,gfvar=x)
  264. ([6, -5], 3*(5 - 21*x)/((x - 1)*(5*x - 1)))
  265. >>> sequence(lucas(n)).find_linear_recurrence(15,gfvar=x)
  266. ([1, 1], (x - 2)/(x**2 + x - 1))
  267. """
  268. from sympy.matrices import Matrix
  269. x = [simplify(expand(t)) for t in self[:n]]
  270. lx = len(x)
  271. if d is None:
  272. r = lx//2
  273. else:
  274. r = min(d,lx//2)
  275. coeffs = []
  276. for l in range(1, r+1):
  277. l2 = 2*l
  278. mlist = []
  279. for k in range(l):
  280. mlist.append(x[k:k+l])
  281. m = Matrix(mlist)
  282. if m.det() != 0:
  283. y = simplify(m.LUsolve(Matrix(x[l:l2])))
  284. if lx == l2:
  285. coeffs = flatten(y[::-1])
  286. break
  287. mlist = []
  288. for k in range(l,lx-l):
  289. mlist.append(x[k:k+l])
  290. m = Matrix(mlist)
  291. if m*y == Matrix(x[l2:]):
  292. coeffs = flatten(y[::-1])
  293. break
  294. if gfvar is None:
  295. return coeffs
  296. else:
  297. l = len(coeffs)
  298. if l == 0:
  299. return [], None
  300. else:
  301. n, d = x[l-1]*gfvar**(l-1), 1 - coeffs[l-1]*gfvar**l
  302. for i in range(l-1):
  303. n += x[i]*gfvar**i
  304. for j in range(l-i-1):
  305. n -= coeffs[i]*x[j]*gfvar**(i+j+1)
  306. d -= coeffs[i]*gfvar**(i+1)
  307. return coeffs, simplify(factor(n)/factor(d))
  308. class EmptySequence(SeqBase, metaclass=Singleton):
  309. """Represents an empty sequence.
  310. The empty sequence is also available as a singleton as
  311. ``S.EmptySequence``.
  312. Examples
  313. ========
  314. >>> from sympy import EmptySequence, SeqPer
  315. >>> from sympy.abc import x
  316. >>> EmptySequence
  317. EmptySequence
  318. >>> SeqPer((1, 2), (x, 0, 10)) + EmptySequence
  319. SeqPer((1, 2), (x, 0, 10))
  320. >>> SeqPer((1, 2)) * EmptySequence
  321. EmptySequence
  322. >>> EmptySequence.coeff_mul(-1)
  323. EmptySequence
  324. """
  325. @property
  326. def interval(self):
  327. return S.EmptySet
  328. @property
  329. def length(self):
  330. return S.Zero
  331. def coeff_mul(self, coeff):
  332. """See docstring of SeqBase.coeff_mul"""
  333. return self
  334. def __iter__(self):
  335. return iter([])
  336. class SeqExpr(SeqBase):
  337. """Sequence expression class.
  338. Various sequences should inherit from this class.
  339. Examples
  340. ========
  341. >>> from sympy.series.sequences import SeqExpr
  342. >>> from sympy.abc import x
  343. >>> from sympy import Tuple
  344. >>> s = SeqExpr(Tuple(1, 2, 3), Tuple(x, 0, 10))
  345. >>> s.gen
  346. (1, 2, 3)
  347. >>> s.interval
  348. Interval(0, 10)
  349. >>> s.length
  350. 11
  351. See Also
  352. ========
  353. sympy.series.sequences.SeqPer
  354. sympy.series.sequences.SeqFormula
  355. """
  356. @property
  357. def gen(self):
  358. return self.args[0]
  359. @property
  360. def interval(self):
  361. return Interval(self.args[1][1], self.args[1][2])
  362. @property
  363. def start(self):
  364. return self.interval.inf
  365. @property
  366. def stop(self):
  367. return self.interval.sup
  368. @property
  369. def length(self):
  370. return self.stop - self.start + 1
  371. @property
  372. def variables(self):
  373. return (self.args[1][0],)
  374. class SeqPer(SeqExpr):
  375. """
  376. Represents a periodic sequence.
  377. The elements are repeated after a given period.
  378. Examples
  379. ========
  380. >>> from sympy import SeqPer, oo
  381. >>> from sympy.abc import k
  382. >>> s = SeqPer((1, 2, 3), (0, 5))
  383. >>> s.periodical
  384. (1, 2, 3)
  385. >>> s.period
  386. 3
  387. For value at a particular point
  388. >>> s.coeff(3)
  389. 1
  390. supports slicing
  391. >>> s[:]
  392. [1, 2, 3, 1, 2, 3]
  393. iterable
  394. >>> list(s)
  395. [1, 2, 3, 1, 2, 3]
  396. sequence starts from negative infinity
  397. >>> SeqPer((1, 2, 3), (-oo, 0))[0:6]
  398. [1, 2, 3, 1, 2, 3]
  399. Periodic formulas
  400. >>> SeqPer((k, k**2, k**3), (k, 0, oo))[0:6]
  401. [0, 1, 8, 3, 16, 125]
  402. See Also
  403. ========
  404. sympy.series.sequences.SeqFormula
  405. """
  406. def __new__(cls, periodical, limits=None):
  407. periodical = sympify(periodical)
  408. def _find_x(periodical):
  409. free = periodical.free_symbols
  410. if len(periodical.free_symbols) == 1:
  411. return free.pop()
  412. else:
  413. return Dummy('k')
  414. x, start, stop = None, None, None
  415. if limits is None:
  416. x, start, stop = _find_x(periodical), 0, S.Infinity
  417. if is_sequence(limits, Tuple):
  418. if len(limits) == 3:
  419. x, start, stop = limits
  420. elif len(limits) == 2:
  421. x = _find_x(periodical)
  422. start, stop = limits
  423. if not isinstance(x, (Symbol, Idx)) or start is None or stop is None:
  424. raise ValueError('Invalid limits given: %s' % str(limits))
  425. if start is S.NegativeInfinity and stop is S.Infinity:
  426. raise ValueError("Both the start and end value"
  427. "cannot be unbounded")
  428. limits = sympify((x, start, stop))
  429. if is_sequence(periodical, Tuple):
  430. periodical = sympify(tuple(flatten(periodical)))
  431. else:
  432. raise ValueError("invalid period %s should be something "
  433. "like e.g (1, 2) " % periodical)
  434. if Interval(limits[1], limits[2]) is S.EmptySet:
  435. return S.EmptySequence
  436. return Basic.__new__(cls, periodical, limits)
  437. @property
  438. def period(self):
  439. return len(self.gen)
  440. @property
  441. def periodical(self):
  442. return self.gen
  443. def _eval_coeff(self, pt):
  444. if self.start is S.NegativeInfinity:
  445. idx = (self.stop - pt) % self.period
  446. else:
  447. idx = (pt - self.start) % self.period
  448. return self.periodical[idx].subs(self.variables[0], pt)
  449. def _add(self, other):
  450. """See docstring of SeqBase._add"""
  451. if isinstance(other, SeqPer):
  452. per1, lper1 = self.periodical, self.period
  453. per2, lper2 = other.periodical, other.period
  454. per_length = lcm(lper1, lper2)
  455. new_per = []
  456. for x in range(per_length):
  457. ele1 = per1[x % lper1]
  458. ele2 = per2[x % lper2]
  459. new_per.append(ele1 + ele2)
  460. start, stop = self._intersect_interval(other)
  461. return SeqPer(new_per, (self.variables[0], start, stop))
  462. def _mul(self, other):
  463. """See docstring of SeqBase._mul"""
  464. if isinstance(other, SeqPer):
  465. per1, lper1 = self.periodical, self.period
  466. per2, lper2 = other.periodical, other.period
  467. per_length = lcm(lper1, lper2)
  468. new_per = []
  469. for x in range(per_length):
  470. ele1 = per1[x % lper1]
  471. ele2 = per2[x % lper2]
  472. new_per.append(ele1 * ele2)
  473. start, stop = self._intersect_interval(other)
  474. return SeqPer(new_per, (self.variables[0], start, stop))
  475. def coeff_mul(self, coeff):
  476. """See docstring of SeqBase.coeff_mul"""
  477. coeff = sympify(coeff)
  478. per = [x * coeff for x in self.periodical]
  479. return SeqPer(per, self.args[1])
  480. class SeqFormula(SeqExpr):
  481. """
  482. Represents sequence based on a formula.
  483. Elements are generated using a formula.
  484. Examples
  485. ========
  486. >>> from sympy import SeqFormula, oo, Symbol
  487. >>> n = Symbol('n')
  488. >>> s = SeqFormula(n**2, (n, 0, 5))
  489. >>> s.formula
  490. n**2
  491. For value at a particular point
  492. >>> s.coeff(3)
  493. 9
  494. supports slicing
  495. >>> s[:]
  496. [0, 1, 4, 9, 16, 25]
  497. iterable
  498. >>> list(s)
  499. [0, 1, 4, 9, 16, 25]
  500. sequence starts from negative infinity
  501. >>> SeqFormula(n**2, (-oo, 0))[0:6]
  502. [0, 1, 4, 9, 16, 25]
  503. See Also
  504. ========
  505. sympy.series.sequences.SeqPer
  506. """
  507. def __new__(cls, formula, limits=None):
  508. formula = sympify(formula)
  509. def _find_x(formula):
  510. free = formula.free_symbols
  511. if len(free) == 1:
  512. return free.pop()
  513. elif not free:
  514. return Dummy('k')
  515. else:
  516. raise ValueError(
  517. " specify dummy variables for %s. If the formula contains"
  518. " more than one free symbol, a dummy variable should be"
  519. " supplied explicitly e.g., SeqFormula(m*n**2, (n, 0, 5))"
  520. % formula)
  521. x, start, stop = None, None, None
  522. if limits is None:
  523. x, start, stop = _find_x(formula), 0, S.Infinity
  524. if is_sequence(limits, Tuple):
  525. if len(limits) == 3:
  526. x, start, stop = limits
  527. elif len(limits) == 2:
  528. x = _find_x(formula)
  529. start, stop = limits
  530. if not isinstance(x, (Symbol, Idx)) or start is None or stop is None:
  531. raise ValueError('Invalid limits given: %s' % str(limits))
  532. if start is S.NegativeInfinity and stop is S.Infinity:
  533. raise ValueError("Both the start and end value "
  534. "cannot be unbounded")
  535. limits = sympify((x, start, stop))
  536. if Interval(limits[1], limits[2]) is S.EmptySet:
  537. return S.EmptySequence
  538. return Basic.__new__(cls, formula, limits)
  539. @property
  540. def formula(self):
  541. return self.gen
  542. def _eval_coeff(self, pt):
  543. d = self.variables[0]
  544. return self.formula.subs(d, pt)
  545. def _add(self, other):
  546. """See docstring of SeqBase._add"""
  547. if isinstance(other, SeqFormula):
  548. form1, v1 = self.formula, self.variables[0]
  549. form2, v2 = other.formula, other.variables[0]
  550. formula = form1 + form2.subs(v2, v1)
  551. start, stop = self._intersect_interval(other)
  552. return SeqFormula(formula, (v1, start, stop))
  553. def _mul(self, other):
  554. """See docstring of SeqBase._mul"""
  555. if isinstance(other, SeqFormula):
  556. form1, v1 = self.formula, self.variables[0]
  557. form2, v2 = other.formula, other.variables[0]
  558. formula = form1 * form2.subs(v2, v1)
  559. start, stop = self._intersect_interval(other)
  560. return SeqFormula(formula, (v1, start, stop))
  561. def coeff_mul(self, coeff):
  562. """See docstring of SeqBase.coeff_mul"""
  563. coeff = sympify(coeff)
  564. formula = self.formula * coeff
  565. return SeqFormula(formula, self.args[1])
  566. def expand(self, *args, **kwargs):
  567. return SeqFormula(expand(self.formula, *args, **kwargs), self.args[1])
  568. class RecursiveSeq(SeqBase):
  569. """
  570. A finite degree recursive sequence.
  571. Explanation
  572. ===========
  573. That is, a sequence a(n) that depends on a fixed, finite number of its
  574. previous values. The general form is
  575. a(n) = f(a(n - 1), a(n - 2), ..., a(n - d))
  576. for some fixed, positive integer d, where f is some function defined by a
  577. SymPy expression.
  578. Parameters
  579. ==========
  580. recurrence : SymPy expression defining recurrence
  581. This is *not* an equality, only the expression that the nth term is
  582. equal to. For example, if :code:`a(n) = f(a(n - 1), ..., a(n - d))`,
  583. then the expression should be :code:`f(a(n - 1), ..., a(n - d))`.
  584. yn : applied undefined function
  585. Represents the nth term of the sequence as e.g. :code:`y(n)` where
  586. :code:`y` is an undefined function and `n` is the sequence index.
  587. n : symbolic argument
  588. The name of the variable that the recurrence is in, e.g., :code:`n` if
  589. the recurrence function is :code:`y(n)`.
  590. initial : iterable with length equal to the degree of the recurrence
  591. The initial values of the recurrence.
  592. start : start value of sequence (inclusive)
  593. Examples
  594. ========
  595. >>> from sympy import Function, symbols
  596. >>> from sympy.series.sequences import RecursiveSeq
  597. >>> y = Function("y")
  598. >>> n = symbols("n")
  599. >>> fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1])
  600. >>> fib.coeff(3) # Value at a particular point
  601. 2
  602. >>> fib[:6] # supports slicing
  603. [0, 1, 1, 2, 3, 5]
  604. >>> fib.recurrence # inspect recurrence
  605. Eq(y(n), y(n - 2) + y(n - 1))
  606. >>> fib.degree # automatically determine degree
  607. 2
  608. >>> for x in zip(range(10), fib): # supports iteration
  609. ... print(x)
  610. (0, 0)
  611. (1, 1)
  612. (2, 1)
  613. (3, 2)
  614. (4, 3)
  615. (5, 5)
  616. (6, 8)
  617. (7, 13)
  618. (8, 21)
  619. (9, 34)
  620. See Also
  621. ========
  622. sympy.series.sequences.SeqFormula
  623. """
  624. def __new__(cls, recurrence, yn, n, initial=None, start=0):
  625. if not isinstance(yn, AppliedUndef):
  626. raise TypeError("recurrence sequence must be an applied undefined function"
  627. ", found `{}`".format(yn))
  628. if not isinstance(n, Basic) or not n.is_symbol:
  629. raise TypeError("recurrence variable must be a symbol"
  630. ", found `{}`".format(n))
  631. if yn.args != (n,):
  632. raise TypeError("recurrence sequence does not match symbol")
  633. y = yn.func
  634. k = Wild("k", exclude=(n,))
  635. degree = 0
  636. # Find all applications of y in the recurrence and check that:
  637. # 1. The function y is only being used with a single argument; and
  638. # 2. All arguments are n + k for constant negative integers k.
  639. prev_ys = recurrence.find(y)
  640. for prev_y in prev_ys:
  641. if len(prev_y.args) != 1:
  642. raise TypeError("Recurrence should be in a single variable")
  643. shift = prev_y.args[0].match(n + k)[k]
  644. if not (shift.is_constant() and shift.is_integer and shift < 0):
  645. raise TypeError("Recurrence should have constant,"
  646. " negative, integer shifts"
  647. " (found {})".format(prev_y))
  648. if -shift > degree:
  649. degree = -shift
  650. if not initial:
  651. initial = [Dummy("c_{}".format(k)) for k in range(degree)]
  652. if len(initial) != degree:
  653. raise ValueError("Number of initial terms must equal degree")
  654. degree = Integer(degree)
  655. start = sympify(start)
  656. initial = Tuple(*(sympify(x) for x in initial))
  657. seq = Basic.__new__(cls, recurrence, yn, n, initial, start)
  658. seq.cache = {y(start + k): init for k, init in enumerate(initial)}
  659. seq.degree = degree
  660. return seq
  661. @property
  662. def _recurrence(self):
  663. """Equation defining recurrence."""
  664. return self.args[0]
  665. @property
  666. def recurrence(self):
  667. """Equation defining recurrence."""
  668. return Eq(self.yn, self.args[0])
  669. @property
  670. def yn(self):
  671. """Applied function representing the nth term"""
  672. return self.args[1]
  673. @property
  674. def y(self):
  675. """Undefined function for the nth term of the sequence"""
  676. return self.yn.func
  677. @property
  678. def n(self):
  679. """Sequence index symbol"""
  680. return self.args[2]
  681. @property
  682. def initial(self):
  683. """The initial values of the sequence"""
  684. return self.args[3]
  685. @property
  686. def start(self):
  687. """The starting point of the sequence. This point is included"""
  688. return self.args[4]
  689. @property
  690. def stop(self):
  691. """The ending point of the sequence. (oo)"""
  692. return S.Infinity
  693. @property
  694. def interval(self):
  695. """Interval on which sequence is defined."""
  696. return (self.start, S.Infinity)
  697. def _eval_coeff(self, index):
  698. if index - self.start < len(self.cache):
  699. return self.cache[self.y(index)]
  700. for current in range(len(self.cache), index + 1):
  701. # Use xreplace over subs for performance.
  702. # See issue #10697.
  703. seq_index = self.start + current
  704. current_recurrence = self._recurrence.xreplace({self.n: seq_index})
  705. new_term = current_recurrence.xreplace(self.cache)
  706. self.cache[self.y(seq_index)] = new_term
  707. return self.cache[self.y(self.start + current)]
  708. def __iter__(self):
  709. index = self.start
  710. while True:
  711. yield self._eval_coeff(index)
  712. index += 1
  713. def sequence(seq, limits=None):
  714. """
  715. Returns appropriate sequence object.
  716. Explanation
  717. ===========
  718. If ``seq`` is a SymPy sequence, returns :class:`SeqPer` object
  719. otherwise returns :class:`SeqFormula` object.
  720. Examples
  721. ========
  722. >>> from sympy import sequence
  723. >>> from sympy.abc import n
  724. >>> sequence(n**2, (n, 0, 5))
  725. SeqFormula(n**2, (n, 0, 5))
  726. >>> sequence((1, 2, 3), (n, 0, 5))
  727. SeqPer((1, 2, 3), (n, 0, 5))
  728. See Also
  729. ========
  730. sympy.series.sequences.SeqPer
  731. sympy.series.sequences.SeqFormula
  732. """
  733. seq = sympify(seq)
  734. if is_sequence(seq, Tuple):
  735. return SeqPer(seq, limits)
  736. else:
  737. return SeqFormula(seq, limits)
  738. ###############################################################################
  739. # OPERATIONS #
  740. ###############################################################################
  741. class SeqExprOp(SeqBase):
  742. """
  743. Base class for operations on sequences.
  744. Examples
  745. ========
  746. >>> from sympy.series.sequences import SeqExprOp, sequence
  747. >>> from sympy.abc import n
  748. >>> s1 = sequence(n**2, (n, 0, 10))
  749. >>> s2 = sequence((1, 2, 3), (n, 5, 10))
  750. >>> s = SeqExprOp(s1, s2)
  751. >>> s.gen
  752. (n**2, (1, 2, 3))
  753. >>> s.interval
  754. Interval(5, 10)
  755. >>> s.length
  756. 6
  757. See Also
  758. ========
  759. sympy.series.sequences.SeqAdd
  760. sympy.series.sequences.SeqMul
  761. """
  762. @property
  763. def gen(self):
  764. """Generator for the sequence.
  765. returns a tuple of generators of all the argument sequences.
  766. """
  767. return tuple(a.gen for a in self.args)
  768. @property
  769. def interval(self):
  770. """Sequence is defined on the intersection
  771. of all the intervals of respective sequences
  772. """
  773. return Intersection(*(a.interval for a in self.args))
  774. @property
  775. def start(self):
  776. return self.interval.inf
  777. @property
  778. def stop(self):
  779. return self.interval.sup
  780. @property
  781. def variables(self):
  782. """Cumulative of all the bound variables"""
  783. return tuple(flatten([a.variables for a in self.args]))
  784. @property
  785. def length(self):
  786. return self.stop - self.start + 1
  787. class SeqAdd(SeqExprOp):
  788. """Represents term-wise addition of sequences.
  789. Rules:
  790. * The interval on which sequence is defined is the intersection
  791. of respective intervals of sequences.
  792. * Anything + :class:`EmptySequence` remains unchanged.
  793. * Other rules are defined in ``_add`` methods of sequence classes.
  794. Examples
  795. ========
  796. >>> from sympy import EmptySequence, oo, SeqAdd, SeqPer, SeqFormula
  797. >>> from sympy.abc import n
  798. >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), EmptySequence)
  799. SeqPer((1, 2), (n, 0, oo))
  800. >>> SeqAdd(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10)))
  801. EmptySequence
  802. >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2, (n, 0, oo)))
  803. SeqAdd(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo)))
  804. >>> SeqAdd(SeqFormula(n**3), SeqFormula(n**2))
  805. SeqFormula(n**3 + n**2, (n, 0, oo))
  806. See Also
  807. ========
  808. sympy.series.sequences.SeqMul
  809. """
  810. def __new__(cls, *args, **kwargs):
  811. evaluate = kwargs.get('evaluate', global_parameters.evaluate)
  812. # flatten inputs
  813. args = list(args)
  814. # adapted from sympy.sets.sets.Union
  815. def _flatten(arg):
  816. if isinstance(arg, SeqBase):
  817. if isinstance(arg, SeqAdd):
  818. return sum(map(_flatten, arg.args), [])
  819. else:
  820. return [arg]
  821. if iterable(arg):
  822. return sum(map(_flatten, arg), [])
  823. raise TypeError("Input must be Sequences or "
  824. " iterables of Sequences")
  825. args = _flatten(args)
  826. args = [a for a in args if a is not S.EmptySequence]
  827. # Addition of no sequences is EmptySequence
  828. if not args:
  829. return S.EmptySequence
  830. if Intersection(*(a.interval for a in args)) is S.EmptySet:
  831. return S.EmptySequence
  832. # reduce using known rules
  833. if evaluate:
  834. return SeqAdd.reduce(args)
  835. args = list(ordered(args, SeqBase._start_key))
  836. return Basic.__new__(cls, *args)
  837. @staticmethod
  838. def reduce(args):
  839. """Simplify :class:`SeqAdd` using known rules.
  840. Iterates through all pairs and ask the constituent
  841. sequences if they can simplify themselves with any other constituent.
  842. Notes
  843. =====
  844. adapted from ``Union.reduce``
  845. """
  846. new_args = True
  847. while new_args:
  848. for id1, s in enumerate(args):
  849. new_args = False
  850. for id2, t in enumerate(args):
  851. if id1 == id2:
  852. continue
  853. new_seq = s._add(t)
  854. # This returns None if s does not know how to add
  855. # with t. Returns the newly added sequence otherwise
  856. if new_seq is not None:
  857. new_args = [a for a in args if a not in (s, t)]
  858. new_args.append(new_seq)
  859. break
  860. if new_args:
  861. args = new_args
  862. break
  863. if len(args) == 1:
  864. return args.pop()
  865. else:
  866. return SeqAdd(args, evaluate=False)
  867. def _eval_coeff(self, pt):
  868. """adds up the coefficients of all the sequences at point pt"""
  869. return sum(a.coeff(pt) for a in self.args)
  870. class SeqMul(SeqExprOp):
  871. r"""Represents term-wise multiplication of sequences.
  872. Explanation
  873. ===========
  874. Handles multiplication of sequences only. For multiplication
  875. with other objects see :func:`SeqBase.coeff_mul`.
  876. Rules:
  877. * The interval on which sequence is defined is the intersection
  878. of respective intervals of sequences.
  879. * Anything \* :class:`EmptySequence` returns :class:`EmptySequence`.
  880. * Other rules are defined in ``_mul`` methods of sequence classes.
  881. Examples
  882. ========
  883. >>> from sympy import EmptySequence, oo, SeqMul, SeqPer, SeqFormula
  884. >>> from sympy.abc import n
  885. >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), EmptySequence)
  886. EmptySequence
  887. >>> SeqMul(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10)))
  888. EmptySequence
  889. >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2))
  890. SeqMul(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo)))
  891. >>> SeqMul(SeqFormula(n**3), SeqFormula(n**2))
  892. SeqFormula(n**5, (n, 0, oo))
  893. See Also
  894. ========
  895. sympy.series.sequences.SeqAdd
  896. """
  897. def __new__(cls, *args, **kwargs):
  898. evaluate = kwargs.get('evaluate', global_parameters.evaluate)
  899. # flatten inputs
  900. args = list(args)
  901. # adapted from sympy.sets.sets.Union
  902. def _flatten(arg):
  903. if isinstance(arg, SeqBase):
  904. if isinstance(arg, SeqMul):
  905. return sum(map(_flatten, arg.args), [])
  906. else:
  907. return [arg]
  908. elif iterable(arg):
  909. return sum(map(_flatten, arg), [])
  910. raise TypeError("Input must be Sequences or "
  911. " iterables of Sequences")
  912. args = _flatten(args)
  913. # Multiplication of no sequences is EmptySequence
  914. if not args:
  915. return S.EmptySequence
  916. if Intersection(*(a.interval for a in args)) is S.EmptySet:
  917. return S.EmptySequence
  918. # reduce using known rules
  919. if evaluate:
  920. return SeqMul.reduce(args)
  921. args = list(ordered(args, SeqBase._start_key))
  922. return Basic.__new__(cls, *args)
  923. @staticmethod
  924. def reduce(args):
  925. """Simplify a :class:`SeqMul` using known rules.
  926. Explanation
  927. ===========
  928. Iterates through all pairs and ask the constituent
  929. sequences if they can simplify themselves with any other constituent.
  930. Notes
  931. =====
  932. adapted from ``Union.reduce``
  933. """
  934. new_args = True
  935. while new_args:
  936. for id1, s in enumerate(args):
  937. new_args = False
  938. for id2, t in enumerate(args):
  939. if id1 == id2:
  940. continue
  941. new_seq = s._mul(t)
  942. # This returns None if s does not know how to multiply
  943. # with t. Returns the newly multiplied sequence otherwise
  944. if new_seq is not None:
  945. new_args = [a for a in args if a not in (s, t)]
  946. new_args.append(new_seq)
  947. break
  948. if new_args:
  949. args = new_args
  950. break
  951. if len(args) == 1:
  952. return args.pop()
  953. else:
  954. return SeqMul(args, evaluate=False)
  955. def _eval_coeff(self, pt):
  956. """multiplies the coefficients of all the sequences at point pt"""
  957. val = 1
  958. for a in self.args:
  959. val *= a.coeff(pt)
  960. return val