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.

610 lines
18 KiB

6 months ago
  1. from typing import Tuple as tTuple
  2. from .expr_with_intlimits import ExprWithIntLimits
  3. from .summations import Sum, summation, _dummy_with_inherited_properties_concrete
  4. from sympy.core.expr import Expr
  5. from sympy.core.exprtools import factor_terms
  6. from sympy.core.function import Derivative
  7. from sympy.core.mul import Mul
  8. from sympy.core.singleton import S
  9. from sympy.core.symbol import Dummy, Symbol
  10. from sympy.functions.combinatorial.factorials import RisingFactorial
  11. from sympy.functions.elementary.exponential import exp, log
  12. from sympy.functions.special.tensor_functions import KroneckerDelta
  13. from sympy.polys import quo, roots
  14. from sympy.simplify.powsimp import powsimp
  15. from sympy.simplify.simplify import product_simplify
  16. class Product(ExprWithIntLimits):
  17. r"""
  18. Represents unevaluated products.
  19. Explanation
  20. ===========
  21. ``Product`` represents a finite or infinite product, with the first
  22. argument being the general form of terms in the series, and the second
  23. argument being ``(dummy_variable, start, end)``, with ``dummy_variable``
  24. taking all integer values from ``start`` through ``end``. In accordance
  25. with long-standing mathematical convention, the end term is included in
  26. the product.
  27. Finite products
  28. ===============
  29. For finite products (and products with symbolic limits assumed to be finite)
  30. we follow the analogue of the summation convention described by Karr [1],
  31. especially definition 3 of section 1.4. The product:
  32. .. math::
  33. \prod_{m \leq i < n} f(i)
  34. has *the obvious meaning* for `m < n`, namely:
  35. .. math::
  36. \prod_{m \leq i < n} f(i) = f(m) f(m+1) \cdot \ldots \cdot f(n-2) f(n-1)
  37. with the upper limit value `f(n)` excluded. The product over an empty set is
  38. one if and only if `m = n`:
  39. .. math::
  40. \prod_{m \leq i < n} f(i) = 1 \quad \mathrm{for} \quad m = n
  41. Finally, for all other products over empty sets we assume the following
  42. definition:
  43. .. math::
  44. \prod_{m \leq i < n} f(i) = \frac{1}{\prod_{n \leq i < m} f(i)} \quad \mathrm{for} \quad m > n
  45. It is important to note that above we define all products with the upper
  46. limit being exclusive. This is in contrast to the usual mathematical notation,
  47. but does not affect the product convention. Indeed we have:
  48. .. math::
  49. \prod_{m \leq i < n} f(i) = \prod_{i = m}^{n - 1} f(i)
  50. where the difference in notation is intentional to emphasize the meaning,
  51. with limits typeset on the top being inclusive.
  52. Examples
  53. ========
  54. >>> from sympy.abc import a, b, i, k, m, n, x
  55. >>> from sympy import Product, oo
  56. >>> Product(k, (k, 1, m))
  57. Product(k, (k, 1, m))
  58. >>> Product(k, (k, 1, m)).doit()
  59. factorial(m)
  60. >>> Product(k**2,(k, 1, m))
  61. Product(k**2, (k, 1, m))
  62. >>> Product(k**2,(k, 1, m)).doit()
  63. factorial(m)**2
  64. Wallis' product for pi:
  65. >>> W = Product(2*i/(2*i-1) * 2*i/(2*i+1), (i, 1, oo))
  66. >>> W
  67. Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo))
  68. Direct computation currently fails:
  69. >>> W.doit()
  70. Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo))
  71. But we can approach the infinite product by a limit of finite products:
  72. >>> from sympy import limit
  73. >>> W2 = Product(2*i/(2*i-1)*2*i/(2*i+1), (i, 1, n))
  74. >>> W2
  75. Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, n))
  76. >>> W2e = W2.doit()
  77. >>> W2e
  78. 4**n*factorial(n)**2/(2**(2*n)*RisingFactorial(1/2, n)*RisingFactorial(3/2, n))
  79. >>> limit(W2e, n, oo)
  80. pi/2
  81. By the same formula we can compute sin(pi/2):
  82. >>> from sympy import combsimp, pi, gamma, simplify
  83. >>> P = pi * x * Product(1 - x**2/k**2, (k, 1, n))
  84. >>> P = P.subs(x, pi/2)
  85. >>> P
  86. pi**2*Product(1 - pi**2/(4*k**2), (k, 1, n))/2
  87. >>> Pe = P.doit()
  88. >>> Pe
  89. pi**2*RisingFactorial(1 - pi/2, n)*RisingFactorial(1 + pi/2, n)/(2*factorial(n)**2)
  90. >>> limit(Pe, n, oo).gammasimp()
  91. sin(pi**2/2)
  92. >>> Pe.rewrite(gamma)
  93. (-1)**n*pi**2*gamma(pi/2)*gamma(n + 1 + pi/2)/(2*gamma(1 + pi/2)*gamma(-n + pi/2)*gamma(n + 1)**2)
  94. Products with the lower limit being larger than the upper one:
  95. >>> Product(1/i, (i, 6, 1)).doit()
  96. 120
  97. >>> Product(i, (i, 2, 5)).doit()
  98. 120
  99. The empty product:
  100. >>> Product(i, (i, n, n-1)).doit()
  101. 1
  102. An example showing that the symbolic result of a product is still
  103. valid for seemingly nonsensical values of the limits. Then the Karr
  104. convention allows us to give a perfectly valid interpretation to
  105. those products by interchanging the limits according to the above rules:
  106. >>> P = Product(2, (i, 10, n)).doit()
  107. >>> P
  108. 2**(n - 9)
  109. >>> P.subs(n, 5)
  110. 1/16
  111. >>> Product(2, (i, 10, 5)).doit()
  112. 1/16
  113. >>> 1/Product(2, (i, 6, 9)).doit()
  114. 1/16
  115. An explicit example of the Karr summation convention applied to products:
  116. >>> P1 = Product(x, (i, a, b)).doit()
  117. >>> P1
  118. x**(-a + b + 1)
  119. >>> P2 = Product(x, (i, b+1, a-1)).doit()
  120. >>> P2
  121. x**(a - b - 1)
  122. >>> simplify(P1 * P2)
  123. 1
  124. And another one:
  125. >>> P1 = Product(i, (i, b, a)).doit()
  126. >>> P1
  127. RisingFactorial(b, a - b + 1)
  128. >>> P2 = Product(i, (i, a+1, b-1)).doit()
  129. >>> P2
  130. RisingFactorial(a + 1, -a + b - 1)
  131. >>> P1 * P2
  132. RisingFactorial(b, a - b + 1)*RisingFactorial(a + 1, -a + b - 1)
  133. >>> combsimp(P1 * P2)
  134. 1
  135. See Also
  136. ========
  137. Sum, summation
  138. product
  139. References
  140. ==========
  141. .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM,
  142. Volume 28 Issue 2, April 1981, Pages 305-350
  143. http://dl.acm.org/citation.cfm?doid=322248.322255
  144. .. [2] https://en.wikipedia.org/wiki/Multiplication#Capital_Pi_notation
  145. .. [3] https://en.wikipedia.org/wiki/Empty_product
  146. """
  147. __slots__ = ('is_commutative',)
  148. limits: tTuple[tTuple[Symbol, Expr, Expr]]
  149. def __new__(cls, function, *symbols, **assumptions):
  150. obj = ExprWithIntLimits.__new__(cls, function, *symbols, **assumptions)
  151. return obj
  152. def _eval_rewrite_as_Sum(self, *args, **kwargs):
  153. return exp(Sum(log(self.function), *self.limits))
  154. @property
  155. def term(self):
  156. return self._args[0]
  157. function = term
  158. def _eval_is_zero(self):
  159. if self.has_empty_sequence:
  160. return False
  161. z = self.term.is_zero
  162. if z is True:
  163. return True
  164. if self.has_finite_limits:
  165. # A Product is zero only if its term is zero assuming finite limits.
  166. return z
  167. def _eval_is_extended_real(self):
  168. if self.has_empty_sequence:
  169. return True
  170. return self.function.is_extended_real
  171. def _eval_is_positive(self):
  172. if self.has_empty_sequence:
  173. return True
  174. if self.function.is_positive and self.has_finite_limits:
  175. return True
  176. def _eval_is_nonnegative(self):
  177. if self.has_empty_sequence:
  178. return True
  179. if self.function.is_nonnegative and self.has_finite_limits:
  180. return True
  181. def _eval_is_extended_nonnegative(self):
  182. if self.has_empty_sequence:
  183. return True
  184. if self.function.is_extended_nonnegative:
  185. return True
  186. def _eval_is_extended_nonpositive(self):
  187. if self.has_empty_sequence:
  188. return True
  189. def _eval_is_finite(self):
  190. if self.has_finite_limits and self.function.is_finite:
  191. return True
  192. def doit(self, **hints):
  193. # first make sure any definite limits have product
  194. # variables with matching assumptions
  195. reps = {}
  196. for xab in self.limits:
  197. d = _dummy_with_inherited_properties_concrete(xab)
  198. if d:
  199. reps[xab[0]] = d
  200. if reps:
  201. undo = {v: k for k, v in reps.items()}
  202. did = self.xreplace(reps).doit(**hints)
  203. if isinstance(did, tuple): # when separate=True
  204. did = tuple([i.xreplace(undo) for i in did])
  205. else:
  206. did = did.xreplace(undo)
  207. return did
  208. f = self.function
  209. for index, limit in enumerate(self.limits):
  210. i, a, b = limit
  211. dif = b - a
  212. if dif.is_integer and dif.is_negative:
  213. a, b = b + 1, a - 1
  214. f = 1 / f
  215. g = self._eval_product(f, (i, a, b))
  216. if g in (None, S.NaN):
  217. return self.func(powsimp(f), *self.limits[index:])
  218. else:
  219. f = g
  220. if hints.get('deep', True):
  221. return f.doit(**hints)
  222. else:
  223. return powsimp(f)
  224. def _eval_adjoint(self):
  225. if self.is_commutative:
  226. return self.func(self.function.adjoint(), *self.limits)
  227. return None
  228. def _eval_conjugate(self):
  229. return self.func(self.function.conjugate(), *self.limits)
  230. def _eval_product(self, term, limits):
  231. (k, a, n) = limits
  232. if k not in term.free_symbols:
  233. if (term - 1).is_zero:
  234. return S.One
  235. return term**(n - a + 1)
  236. if a == n:
  237. return term.subs(k, a)
  238. from .delta import deltaproduct, _has_simple_delta
  239. if term.has(KroneckerDelta) and _has_simple_delta(term, limits[0]):
  240. return deltaproduct(term, limits)
  241. dif = n - a
  242. definite = dif.is_Integer
  243. if definite and (dif < 100):
  244. return self._eval_product_direct(term, limits)
  245. elif term.is_polynomial(k):
  246. poly = term.as_poly(k)
  247. A = B = Q = S.One
  248. all_roots = roots(poly)
  249. M = 0
  250. for r, m in all_roots.items():
  251. M += m
  252. A *= RisingFactorial(a - r, n - a + 1)**m
  253. Q *= (n - r)**m
  254. if M < poly.degree():
  255. arg = quo(poly, Q.as_poly(k))
  256. B = self.func(arg, (k, a, n)).doit()
  257. return poly.LC()**(n - a + 1) * A * B
  258. elif term.is_Add:
  259. factored = factor_terms(term, fraction=True)
  260. if factored.is_Mul:
  261. return self._eval_product(factored, (k, a, n))
  262. elif term.is_Mul:
  263. # Factor in part without the summation variable and part with
  264. without_k, with_k = term.as_coeff_mul(k)
  265. if len(with_k) >= 2:
  266. # More than one term including k, so still a multiplication
  267. exclude, include = [], []
  268. for t in with_k:
  269. p = self._eval_product(t, (k, a, n))
  270. if p is not None:
  271. exclude.append(p)
  272. else:
  273. include.append(t)
  274. if not exclude:
  275. return None
  276. else:
  277. arg = term._new_rawargs(*include)
  278. A = Mul(*exclude)
  279. B = self.func(arg, (k, a, n)).doit()
  280. return without_k**(n - a + 1)*A * B
  281. else:
  282. # Just a single term
  283. p = self._eval_product(with_k[0], (k, a, n))
  284. if p is None:
  285. p = self.func(with_k[0], (k, a, n)).doit()
  286. return without_k**(n - a + 1)*p
  287. elif term.is_Pow:
  288. if not term.base.has(k):
  289. s = summation(term.exp, (k, a, n))
  290. return term.base**s
  291. elif not term.exp.has(k):
  292. p = self._eval_product(term.base, (k, a, n))
  293. if p is not None:
  294. return p**term.exp
  295. elif isinstance(term, Product):
  296. evaluated = term.doit()
  297. f = self._eval_product(evaluated, limits)
  298. if f is None:
  299. return self.func(evaluated, limits)
  300. else:
  301. return f
  302. if definite:
  303. return self._eval_product_direct(term, limits)
  304. def _eval_simplify(self, **kwargs):
  305. rv = product_simplify(self)
  306. return rv.doit() if kwargs['doit'] else rv
  307. def _eval_transpose(self):
  308. if self.is_commutative:
  309. return self.func(self.function.transpose(), *self.limits)
  310. return None
  311. def _eval_product_direct(self, term, limits):
  312. (k, a, n) = limits
  313. return Mul(*[term.subs(k, a + i) for i in range(n - a + 1)])
  314. def _eval_derivative(self, x):
  315. if isinstance(x, Symbol) and x not in self.free_symbols:
  316. return S.Zero
  317. f, limits = self.function, list(self.limits)
  318. limit = limits.pop(-1)
  319. if limits:
  320. f = self.func(f, *limits)
  321. i, a, b = limit
  322. if x in a.free_symbols or x in b.free_symbols:
  323. return None
  324. h = Dummy()
  325. rv = Sum( Product(f, (i, a, h - 1)) * Product(f, (i, h + 1, b)) * Derivative(f, x, evaluate=True).subs(i, h), (h, a, b))
  326. return rv
  327. def is_convergent(self):
  328. r"""
  329. See docs of :obj:`.Sum.is_convergent()` for explanation of convergence
  330. in SymPy.
  331. Explanation
  332. ===========
  333. The infinite product:
  334. .. math::
  335. \prod_{1 \leq i < \infty} f(i)
  336. is defined by the sequence of partial products:
  337. .. math::
  338. \prod_{i=1}^{n} f(i) = f(1) f(2) \cdots f(n)
  339. as n increases without bound. The product converges to a non-zero
  340. value if and only if the sum:
  341. .. math::
  342. \sum_{1 \leq i < \infty} \log{f(n)}
  343. converges.
  344. Examples
  345. ========
  346. >>> from sympy import Product, Symbol, cos, pi, exp, oo
  347. >>> n = Symbol('n', integer=True)
  348. >>> Product(n/(n + 1), (n, 1, oo)).is_convergent()
  349. False
  350. >>> Product(1/n**2, (n, 1, oo)).is_convergent()
  351. False
  352. >>> Product(cos(pi/n), (n, 1, oo)).is_convergent()
  353. True
  354. >>> Product(exp(-n**2), (n, 1, oo)).is_convergent()
  355. False
  356. References
  357. ==========
  358. .. [1] https://en.wikipedia.org/wiki/Infinite_product
  359. """
  360. sequence_term = self.function
  361. log_sum = log(sequence_term)
  362. lim = self.limits
  363. try:
  364. is_conv = Sum(log_sum, *lim).is_convergent()
  365. except NotImplementedError:
  366. if Sum(sequence_term - 1, *lim).is_absolutely_convergent() is S.true:
  367. return S.true
  368. raise NotImplementedError("The algorithm to find the product convergence of %s "
  369. "is not yet implemented" % (sequence_term))
  370. return is_conv
  371. def reverse_order(expr, *indices):
  372. """
  373. Reverse the order of a limit in a Product.
  374. Explanation
  375. ===========
  376. ``reverse_order(expr, *indices)`` reverses some limits in the expression
  377. ``expr`` which can be either a ``Sum`` or a ``Product``. The selectors in
  378. the argument ``indices`` specify some indices whose limits get reversed.
  379. These selectors are either variable names or numerical indices counted
  380. starting from the inner-most limit tuple.
  381. Examples
  382. ========
  383. >>> from sympy import gamma, Product, simplify, Sum
  384. >>> from sympy.abc import x, y, a, b, c, d
  385. >>> P = Product(x, (x, a, b))
  386. >>> Pr = P.reverse_order(x)
  387. >>> Pr
  388. Product(1/x, (x, b + 1, a - 1))
  389. >>> Pr = Pr.doit()
  390. >>> Pr
  391. 1/RisingFactorial(b + 1, a - b - 1)
  392. >>> simplify(Pr.rewrite(gamma))
  393. Piecewise((gamma(b + 1)/gamma(a), b > -1), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True))
  394. >>> P = P.doit()
  395. >>> P
  396. RisingFactorial(a, -a + b + 1)
  397. >>> simplify(P.rewrite(gamma))
  398. Piecewise((gamma(b + 1)/gamma(a), a > 0), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True))
  399. While one should prefer variable names when specifying which limits
  400. to reverse, the index counting notation comes in handy in case there
  401. are several symbols with the same name.
  402. >>> S = Sum(x*y, (x, a, b), (y, c, d))
  403. >>> S
  404. Sum(x*y, (x, a, b), (y, c, d))
  405. >>> S0 = S.reverse_order(0)
  406. >>> S0
  407. Sum(-x*y, (x, b + 1, a - 1), (y, c, d))
  408. >>> S1 = S0.reverse_order(1)
  409. >>> S1
  410. Sum(x*y, (x, b + 1, a - 1), (y, d + 1, c - 1))
  411. Of course we can mix both notations:
  412. >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1)
  413. Sum(x*y, (x, b + 1, a - 1), (y, 6, 1))
  414. >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x)
  415. Sum(x*y, (x, b + 1, a - 1), (y, 6, 1))
  416. See Also
  417. ========
  418. sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index,
  419. reorder_limit,
  420. sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder
  421. References
  422. ==========
  423. .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM,
  424. Volume 28 Issue 2, April 1981, Pages 305-350
  425. http://dl.acm.org/citation.cfm?doid=322248.322255
  426. """
  427. l_indices = list(indices)
  428. for i, indx in enumerate(l_indices):
  429. if not isinstance(indx, int):
  430. l_indices[i] = expr.index(indx)
  431. e = 1
  432. limits = []
  433. for i, limit in enumerate(expr.limits):
  434. l = limit
  435. if i in l_indices:
  436. e = -e
  437. l = (limit[0], limit[2] + 1, limit[1] - 1)
  438. limits.append(l)
  439. return Product(expr.function ** e, *limits)
  440. def product(*args, **kwargs):
  441. r"""
  442. Compute the product.
  443. Explanation
  444. ===========
  445. The notation for symbols is similar to the notation used in Sum or
  446. Integral. product(f, (i, a, b)) computes the product of f with
  447. respect to i from a to b, i.e.,
  448. ::
  449. b
  450. _____
  451. product(f(n), (i, a, b)) = | | f(n)
  452. | |
  453. i = a
  454. If it cannot compute the product, it returns an unevaluated Product object.
  455. Repeated products can be computed by introducing additional symbols tuples::
  456. Examples
  457. ========
  458. >>> from sympy import product, symbols
  459. >>> i, n, m, k = symbols('i n m k', integer=True)
  460. >>> product(i, (i, 1, k))
  461. factorial(k)
  462. >>> product(m, (i, 1, k))
  463. m**k
  464. >>> product(i, (i, 1, k), (k, 1, n))
  465. Product(factorial(k), (k, 1, n))
  466. """
  467. prod = Product(*args, **kwargs)
  468. if isinstance(prod, Product):
  469. return prod.doit(deep=False)
  470. else:
  471. return prod