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.

352 lines
11 KiB

6 months ago
  1. from sympy.concrete.expr_with_limits import ExprWithLimits
  2. from sympy.core.singleton import S
  3. from sympy.core.relational import Eq
  4. class ReorderError(NotImplementedError):
  5. """
  6. Exception raised when trying to reorder dependent limits.
  7. """
  8. def __init__(self, expr, msg):
  9. super().__init__(
  10. "%s could not be reordered: %s." % (expr, msg))
  11. class ExprWithIntLimits(ExprWithLimits):
  12. """
  13. Superclass for Product and Sum.
  14. See Also
  15. ========
  16. sympy.concrete.expr_with_limits.ExprWithLimits
  17. sympy.concrete.products.Product
  18. sympy.concrete.summations.Sum
  19. """
  20. def change_index(self, var, trafo, newvar=None):
  21. r"""
  22. Change index of a Sum or Product.
  23. Perform a linear transformation `x \mapsto a x + b` on the index variable
  24. `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used
  25. after the change of index can also be specified.
  26. Explanation
  27. ===========
  28. ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the
  29. index variable `x` to transform. The transformation ``trafo`` must be linear
  30. and given in terms of ``var``. If the optional argument ``newvar`` is
  31. provided then ``var`` gets replaced by ``newvar`` in the final expression.
  32. Examples
  33. ========
  34. >>> from sympy import Sum, Product, simplify
  35. >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l
  36. >>> S = Sum(x, (x, a, b))
  37. >>> S.doit()
  38. -a**2/2 + a/2 + b**2/2 + b/2
  39. >>> Sn = S.change_index(x, x + 1, y)
  40. >>> Sn
  41. Sum(y - 1, (y, a + 1, b + 1))
  42. >>> Sn.doit()
  43. -a**2/2 + a/2 + b**2/2 + b/2
  44. >>> Sn = S.change_index(x, -x, y)
  45. >>> Sn
  46. Sum(-y, (y, -b, -a))
  47. >>> Sn.doit()
  48. -a**2/2 + a/2 + b**2/2 + b/2
  49. >>> Sn = S.change_index(x, x+u)
  50. >>> Sn
  51. Sum(-u + x, (x, a + u, b + u))
  52. >>> Sn.doit()
  53. -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
  54. >>> simplify(Sn.doit())
  55. -a**2/2 + a/2 + b**2/2 + b/2
  56. >>> Sn = S.change_index(x, -x - u, y)
  57. >>> Sn
  58. Sum(-u - y, (y, -b - u, -a - u))
  59. >>> Sn.doit()
  60. -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u
  61. >>> simplify(Sn.doit())
  62. -a**2/2 + a/2 + b**2/2 + b/2
  63. >>> P = Product(i*j**2, (i, a, b), (j, c, d))
  64. >>> P
  65. Product(i*j**2, (i, a, b), (j, c, d))
  66. >>> P2 = P.change_index(i, i+3, k)
  67. >>> P2
  68. Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d))
  69. >>> P3 = P2.change_index(j, -j, l)
  70. >>> P3
  71. Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c))
  72. When dealing with symbols only, we can make a
  73. general linear transformation:
  74. >>> Sn = S.change_index(x, u*x+v, y)
  75. >>> Sn
  76. Sum((-v + y)/u, (y, b*u + v, a*u + v))
  77. >>> Sn.doit()
  78. -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u
  79. >>> simplify(Sn.doit())
  80. a**2*u/2 + a/2 - b**2*u/2 + b/2
  81. However, the last result can be inconsistent with usual
  82. summation where the index increment is always 1. This is
  83. obvious as we get back the original value only for ``u``
  84. equal +1 or -1.
  85. See Also
  86. ========
  87. sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index,
  88. reorder_limit,
  89. sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder,
  90. sympy.concrete.summations.Sum.reverse_order,
  91. sympy.concrete.products.Product.reverse_order
  92. """
  93. if newvar is None:
  94. newvar = var
  95. limits = []
  96. for limit in self.limits:
  97. if limit[0] == var:
  98. p = trafo.as_poly(var)
  99. if p.degree() != 1:
  100. raise ValueError("Index transformation is not linear")
  101. alpha = p.coeff_monomial(var)
  102. beta = p.coeff_monomial(S.One)
  103. if alpha.is_number:
  104. if alpha == S.One:
  105. limits.append((newvar, alpha*limit[1] + beta, alpha*limit[2] + beta))
  106. elif alpha == S.NegativeOne:
  107. limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta))
  108. else:
  109. raise ValueError("Linear transformation results in non-linear summation stepsize")
  110. else:
  111. # Note that the case of alpha being symbolic can give issues if alpha < 0.
  112. limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta))
  113. else:
  114. limits.append(limit)
  115. function = self.function.subs(var, (var - beta)/alpha)
  116. function = function.subs(var, newvar)
  117. return self.func(function, *limits)
  118. def index(expr, x):
  119. """
  120. Return the index of a dummy variable in the list of limits.
  121. Explanation
  122. ===========
  123. ``index(expr, x)`` returns the index of the dummy variable ``x`` in the
  124. limits of ``expr``. Note that we start counting with 0 at the inner-most
  125. limits tuple.
  126. Examples
  127. ========
  128. >>> from sympy.abc import x, y, a, b, c, d
  129. >>> from sympy import Sum, Product
  130. >>> Sum(x*y, (x, a, b), (y, c, d)).index(x)
  131. 0
  132. >>> Sum(x*y, (x, a, b), (y, c, d)).index(y)
  133. 1
  134. >>> Product(x*y, (x, a, b), (y, c, d)).index(x)
  135. 0
  136. >>> Product(x*y, (x, a, b), (y, c, d)).index(y)
  137. 1
  138. See Also
  139. ========
  140. reorder_limit, reorder, sympy.concrete.summations.Sum.reverse_order,
  141. sympy.concrete.products.Product.reverse_order
  142. """
  143. variables = [limit[0] for limit in expr.limits]
  144. if variables.count(x) != 1:
  145. raise ValueError(expr, "Number of instances of variable not equal to one")
  146. else:
  147. return variables.index(x)
  148. def reorder(expr, *arg):
  149. """
  150. Reorder limits in a expression containing a Sum or a Product.
  151. Explanation
  152. ===========
  153. ``expr.reorder(*arg)`` reorders the limits in the expression ``expr``
  154. according to the list of tuples given by ``arg``. These tuples can
  155. contain numerical indices or index variable names or involve both.
  156. Examples
  157. ========
  158. >>> from sympy import Sum, Product
  159. >>> from sympy.abc import x, y, z, a, b, c, d, e, f
  160. >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((x, y))
  161. Sum(x*y, (y, c, d), (x, a, b))
  162. >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder((x, y), (x, z), (y, z))
  163. Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b))
  164. >>> P = Product(x*y*z, (x, a, b), (y, c, d), (z, e, f))
  165. >>> P.reorder((x, y), (x, z), (y, z))
  166. Product(x*y*z, (z, e, f), (y, c, d), (x, a, b))
  167. We can also select the index variables by counting them, starting
  168. with the inner-most one:
  169. >>> Sum(x**2, (x, a, b), (x, c, d)).reorder((0, 1))
  170. Sum(x**2, (x, c, d), (x, a, b))
  171. And of course we can mix both schemes:
  172. >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, x))
  173. Sum(x*y, (y, c, d), (x, a, b))
  174. >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, 0))
  175. Sum(x*y, (y, c, d), (x, a, b))
  176. See Also
  177. ========
  178. reorder_limit, index, sympy.concrete.summations.Sum.reverse_order,
  179. sympy.concrete.products.Product.reverse_order
  180. """
  181. new_expr = expr
  182. for r in arg:
  183. if len(r) != 2:
  184. raise ValueError(r, "Invalid number of arguments")
  185. index1 = r[0]
  186. index2 = r[1]
  187. if not isinstance(r[0], int):
  188. index1 = expr.index(r[0])
  189. if not isinstance(r[1], int):
  190. index2 = expr.index(r[1])
  191. new_expr = new_expr.reorder_limit(index1, index2)
  192. return new_expr
  193. def reorder_limit(expr, x, y):
  194. """
  195. Interchange two limit tuples of a Sum or Product expression.
  196. Explanation
  197. ===========
  198. ``expr.reorder_limit(x, y)`` interchanges two limit tuples. The
  199. arguments ``x`` and ``y`` are integers corresponding to the index
  200. variables of the two limits which are to be interchanged. The
  201. expression ``expr`` has to be either a Sum or a Product.
  202. Examples
  203. ========
  204. >>> from sympy.abc import x, y, z, a, b, c, d, e, f
  205. >>> from sympy import Sum, Product
  206. >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2)
  207. Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b))
  208. >>> Sum(x**2, (x, a, b), (x, c, d)).reorder_limit(1, 0)
  209. Sum(x**2, (x, c, d), (x, a, b))
  210. >>> Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2)
  211. Product(x*y*z, (z, e, f), (y, c, d), (x, a, b))
  212. See Also
  213. ========
  214. index, reorder, sympy.concrete.summations.Sum.reverse_order,
  215. sympy.concrete.products.Product.reverse_order
  216. """
  217. var = {limit[0] for limit in expr.limits}
  218. limit_x = expr.limits[x]
  219. limit_y = expr.limits[y]
  220. if (len(set(limit_x[1].free_symbols).intersection(var)) == 0 and
  221. len(set(limit_x[2].free_symbols).intersection(var)) == 0 and
  222. len(set(limit_y[1].free_symbols).intersection(var)) == 0 and
  223. len(set(limit_y[2].free_symbols).intersection(var)) == 0):
  224. limits = []
  225. for i, limit in enumerate(expr.limits):
  226. if i == x:
  227. limits.append(limit_y)
  228. elif i == y:
  229. limits.append(limit_x)
  230. else:
  231. limits.append(limit)
  232. return type(expr)(expr.function, *limits)
  233. else:
  234. raise ReorderError(expr, "could not interchange the two limits specified")
  235. @property
  236. def has_empty_sequence(self):
  237. """
  238. Returns True if the Sum or Product is computed for an empty sequence.
  239. Examples
  240. ========
  241. >>> from sympy import Sum, Product, Symbol
  242. >>> m = Symbol('m')
  243. >>> Sum(m, (m, 1, 0)).has_empty_sequence
  244. True
  245. >>> Sum(m, (m, 1, 1)).has_empty_sequence
  246. False
  247. >>> M = Symbol('M', integer=True, positive=True)
  248. >>> Product(m, (m, 1, M)).has_empty_sequence
  249. False
  250. >>> Product(m, (m, 2, M)).has_empty_sequence
  251. >>> Product(m, (m, M + 1, M)).has_empty_sequence
  252. True
  253. >>> N = Symbol('N', integer=True, positive=True)
  254. >>> Sum(m, (m, N, M)).has_empty_sequence
  255. >>> N = Symbol('N', integer=True, negative=True)
  256. >>> Sum(m, (m, N, M)).has_empty_sequence
  257. False
  258. See Also
  259. ========
  260. has_reversed_limits
  261. has_finite_limits
  262. """
  263. ret_None = False
  264. for lim in self.limits:
  265. dif = lim[1] - lim[2]
  266. eq = Eq(dif, 1)
  267. if eq == True:
  268. return True
  269. elif eq == False:
  270. continue
  271. else:
  272. ret_None = True
  273. if ret_None:
  274. return None
  275. return False