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.

473 lines
12 KiB

6 months ago
  1. from sympy.core import S, Integer
  2. from sympy.core.function import Function
  3. from sympy.core.logic import fuzzy_not
  4. from sympy.core.mul import prod
  5. from sympy.core.relational import Ne
  6. from sympy.core.sorting import default_sort_key
  7. from sympy.external.gmpy import SYMPY_INTS
  8. from sympy.utilities.iterables import has_dups
  9. ###############################################################################
  10. ###################### Kronecker Delta, Levi-Civita etc. ######################
  11. ###############################################################################
  12. def Eijk(*args, **kwargs):
  13. """
  14. Represent the Levi-Civita symbol.
  15. This is a compatibility wrapper to ``LeviCivita()``.
  16. See Also
  17. ========
  18. LeviCivita
  19. """
  20. return LeviCivita(*args, **kwargs)
  21. def eval_levicivita(*args):
  22. """Evaluate Levi-Civita symbol."""
  23. from sympy.functions.combinatorial.factorials import factorial
  24. n = len(args)
  25. return prod(
  26. prod(args[j] - args[i] for j in range(i + 1, n))
  27. / factorial(i) for i in range(n))
  28. # converting factorial(i) to int is slightly faster
  29. class LeviCivita(Function):
  30. """
  31. Represent the Levi-Civita symbol.
  32. Explanation
  33. ===========
  34. For even permutations of indices it returns 1, for odd permutations -1, and
  35. for everything else (a repeated index) it returns 0.
  36. Thus it represents an alternating pseudotensor.
  37. Examples
  38. ========
  39. >>> from sympy import LeviCivita
  40. >>> from sympy.abc import i, j, k
  41. >>> LeviCivita(1, 2, 3)
  42. 1
  43. >>> LeviCivita(1, 3, 2)
  44. -1
  45. >>> LeviCivita(1, 2, 2)
  46. 0
  47. >>> LeviCivita(i, j, k)
  48. LeviCivita(i, j, k)
  49. >>> LeviCivita(i, j, i)
  50. 0
  51. See Also
  52. ========
  53. Eijk
  54. """
  55. is_integer = True
  56. @classmethod
  57. def eval(cls, *args):
  58. if all(isinstance(a, (SYMPY_INTS, Integer)) for a in args):
  59. return eval_levicivita(*args)
  60. if has_dups(args):
  61. return S.Zero
  62. def doit(self):
  63. return eval_levicivita(*self.args)
  64. class KroneckerDelta(Function):
  65. """
  66. The discrete, or Kronecker, delta function.
  67. Explanation
  68. ===========
  69. A function that takes in two integers $i$ and $j$. It returns $0$ if $i$
  70. and $j$ are not equal, or it returns $1$ if $i$ and $j$ are equal.
  71. Examples
  72. ========
  73. An example with integer indices:
  74. >>> from sympy import KroneckerDelta
  75. >>> KroneckerDelta(1, 2)
  76. 0
  77. >>> KroneckerDelta(3, 3)
  78. 1
  79. Symbolic indices:
  80. >>> from sympy.abc import i, j, k
  81. >>> KroneckerDelta(i, j)
  82. KroneckerDelta(i, j)
  83. >>> KroneckerDelta(i, i)
  84. 1
  85. >>> KroneckerDelta(i, i + 1)
  86. 0
  87. >>> KroneckerDelta(i, i + 1 + k)
  88. KroneckerDelta(i, i + k + 1)
  89. Parameters
  90. ==========
  91. i : Number, Symbol
  92. The first index of the delta function.
  93. j : Number, Symbol
  94. The second index of the delta function.
  95. See Also
  96. ========
  97. eval
  98. DiracDelta
  99. References
  100. ==========
  101. .. [1] https://en.wikipedia.org/wiki/Kronecker_delta
  102. """
  103. is_integer = True
  104. @classmethod
  105. def eval(cls, i, j, delta_range=None):
  106. """
  107. Evaluates the discrete delta function.
  108. Examples
  109. ========
  110. >>> from sympy import KroneckerDelta
  111. >>> from sympy.abc import i, j, k
  112. >>> KroneckerDelta(i, j)
  113. KroneckerDelta(i, j)
  114. >>> KroneckerDelta(i, i)
  115. 1
  116. >>> KroneckerDelta(i, i + 1)
  117. 0
  118. >>> KroneckerDelta(i, i + 1 + k)
  119. KroneckerDelta(i, i + k + 1)
  120. # indirect doctest
  121. """
  122. if delta_range is not None:
  123. dinf, dsup = delta_range
  124. if (dinf - i > 0) == True:
  125. return S.Zero
  126. if (dinf - j > 0) == True:
  127. return S.Zero
  128. if (dsup - i < 0) == True:
  129. return S.Zero
  130. if (dsup - j < 0) == True:
  131. return S.Zero
  132. diff = i - j
  133. if diff.is_zero:
  134. return S.One
  135. elif fuzzy_not(diff.is_zero):
  136. return S.Zero
  137. if i.assumptions0.get("below_fermi") and \
  138. j.assumptions0.get("above_fermi"):
  139. return S.Zero
  140. if j.assumptions0.get("below_fermi") and \
  141. i.assumptions0.get("above_fermi"):
  142. return S.Zero
  143. # to make KroneckerDelta canonical
  144. # following lines will check if inputs are in order
  145. # if not, will return KroneckerDelta with correct order
  146. if i != min(i, j, key=default_sort_key):
  147. if delta_range:
  148. return cls(j, i, delta_range)
  149. else:
  150. return cls(j, i)
  151. @property
  152. def delta_range(self):
  153. if len(self.args) > 2:
  154. return self.args[2]
  155. def _eval_power(self, expt):
  156. if expt.is_positive:
  157. return self
  158. if expt.is_negative and expt is not S.NegativeOne:
  159. return 1/self
  160. @property
  161. def is_above_fermi(self):
  162. """
  163. True if Delta can be non-zero above fermi.
  164. Examples
  165. ========
  166. >>> from sympy import KroneckerDelta, Symbol
  167. >>> a = Symbol('a', above_fermi=True)
  168. >>> i = Symbol('i', below_fermi=True)
  169. >>> p = Symbol('p')
  170. >>> q = Symbol('q')
  171. >>> KroneckerDelta(p, a).is_above_fermi
  172. True
  173. >>> KroneckerDelta(p, i).is_above_fermi
  174. False
  175. >>> KroneckerDelta(p, q).is_above_fermi
  176. True
  177. See Also
  178. ========
  179. is_below_fermi, is_only_below_fermi, is_only_above_fermi
  180. """
  181. if self.args[0].assumptions0.get("below_fermi"):
  182. return False
  183. if self.args[1].assumptions0.get("below_fermi"):
  184. return False
  185. return True
  186. @property
  187. def is_below_fermi(self):
  188. """
  189. True if Delta can be non-zero below fermi.
  190. Examples
  191. ========
  192. >>> from sympy import KroneckerDelta, Symbol
  193. >>> a = Symbol('a', above_fermi=True)
  194. >>> i = Symbol('i', below_fermi=True)
  195. >>> p = Symbol('p')
  196. >>> q = Symbol('q')
  197. >>> KroneckerDelta(p, a).is_below_fermi
  198. False
  199. >>> KroneckerDelta(p, i).is_below_fermi
  200. True
  201. >>> KroneckerDelta(p, q).is_below_fermi
  202. True
  203. See Also
  204. ========
  205. is_above_fermi, is_only_above_fermi, is_only_below_fermi
  206. """
  207. if self.args[0].assumptions0.get("above_fermi"):
  208. return False
  209. if self.args[1].assumptions0.get("above_fermi"):
  210. return False
  211. return True
  212. @property
  213. def is_only_above_fermi(self):
  214. """
  215. True if Delta is restricted to above fermi.
  216. Examples
  217. ========
  218. >>> from sympy import KroneckerDelta, Symbol
  219. >>> a = Symbol('a', above_fermi=True)
  220. >>> i = Symbol('i', below_fermi=True)
  221. >>> p = Symbol('p')
  222. >>> q = Symbol('q')
  223. >>> KroneckerDelta(p, a).is_only_above_fermi
  224. True
  225. >>> KroneckerDelta(p, q).is_only_above_fermi
  226. False
  227. >>> KroneckerDelta(p, i).is_only_above_fermi
  228. False
  229. See Also
  230. ========
  231. is_above_fermi, is_below_fermi, is_only_below_fermi
  232. """
  233. return ( self.args[0].assumptions0.get("above_fermi")
  234. or
  235. self.args[1].assumptions0.get("above_fermi")
  236. ) or False
  237. @property
  238. def is_only_below_fermi(self):
  239. """
  240. True if Delta is restricted to below fermi.
  241. Examples
  242. ========
  243. >>> from sympy import KroneckerDelta, Symbol
  244. >>> a = Symbol('a', above_fermi=True)
  245. >>> i = Symbol('i', below_fermi=True)
  246. >>> p = Symbol('p')
  247. >>> q = Symbol('q')
  248. >>> KroneckerDelta(p, i).is_only_below_fermi
  249. True
  250. >>> KroneckerDelta(p, q).is_only_below_fermi
  251. False
  252. >>> KroneckerDelta(p, a).is_only_below_fermi
  253. False
  254. See Also
  255. ========
  256. is_above_fermi, is_below_fermi, is_only_above_fermi
  257. """
  258. return ( self.args[0].assumptions0.get("below_fermi")
  259. or
  260. self.args[1].assumptions0.get("below_fermi")
  261. ) or False
  262. @property
  263. def indices_contain_equal_information(self):
  264. """
  265. Returns True if indices are either both above or below fermi.
  266. Examples
  267. ========
  268. >>> from sympy import KroneckerDelta, Symbol
  269. >>> a = Symbol('a', above_fermi=True)
  270. >>> i = Symbol('i', below_fermi=True)
  271. >>> p = Symbol('p')
  272. >>> q = Symbol('q')
  273. >>> KroneckerDelta(p, q).indices_contain_equal_information
  274. True
  275. >>> KroneckerDelta(p, q+1).indices_contain_equal_information
  276. True
  277. >>> KroneckerDelta(i, p).indices_contain_equal_information
  278. False
  279. """
  280. if (self.args[0].assumptions0.get("below_fermi") and
  281. self.args[1].assumptions0.get("below_fermi")):
  282. return True
  283. if (self.args[0].assumptions0.get("above_fermi")
  284. and self.args[1].assumptions0.get("above_fermi")):
  285. return True
  286. # if both indices are general we are True, else false
  287. return self.is_below_fermi and self.is_above_fermi
  288. @property
  289. def preferred_index(self):
  290. """
  291. Returns the index which is preferred to keep in the final expression.
  292. Explanation
  293. ===========
  294. The preferred index is the index with more information regarding fermi
  295. level. If indices contain the same information, 'a' is preferred before
  296. 'b'.
  297. Examples
  298. ========
  299. >>> from sympy import KroneckerDelta, Symbol
  300. >>> a = Symbol('a', above_fermi=True)
  301. >>> i = Symbol('i', below_fermi=True)
  302. >>> j = Symbol('j', below_fermi=True)
  303. >>> p = Symbol('p')
  304. >>> KroneckerDelta(p, i).preferred_index
  305. i
  306. >>> KroneckerDelta(p, a).preferred_index
  307. a
  308. >>> KroneckerDelta(i, j).preferred_index
  309. i
  310. See Also
  311. ========
  312. killable_index
  313. """
  314. if self._get_preferred_index():
  315. return self.args[1]
  316. else:
  317. return self.args[0]
  318. @property
  319. def killable_index(self):
  320. """
  321. Returns the index which is preferred to substitute in the final
  322. expression.
  323. Explanation
  324. ===========
  325. The index to substitute is the index with less information regarding
  326. fermi level. If indices contain the same information, 'a' is preferred
  327. before 'b'.
  328. Examples
  329. ========
  330. >>> from sympy import KroneckerDelta, Symbol
  331. >>> a = Symbol('a', above_fermi=True)
  332. >>> i = Symbol('i', below_fermi=True)
  333. >>> j = Symbol('j', below_fermi=True)
  334. >>> p = Symbol('p')
  335. >>> KroneckerDelta(p, i).killable_index
  336. p
  337. >>> KroneckerDelta(p, a).killable_index
  338. p
  339. >>> KroneckerDelta(i, j).killable_index
  340. j
  341. See Also
  342. ========
  343. preferred_index
  344. """
  345. if self._get_preferred_index():
  346. return self.args[0]
  347. else:
  348. return self.args[1]
  349. def _get_preferred_index(self):
  350. """
  351. Returns the index which is preferred to keep in the final expression.
  352. The preferred index is the index with more information regarding fermi
  353. level. If indices contain the same information, index 0 is returned.
  354. """
  355. if not self.is_above_fermi:
  356. if self.args[0].assumptions0.get("below_fermi"):
  357. return 0
  358. else:
  359. return 1
  360. elif not self.is_below_fermi:
  361. if self.args[0].assumptions0.get("above_fermi"):
  362. return 0
  363. else:
  364. return 1
  365. else:
  366. return 0
  367. @property
  368. def indices(self):
  369. return self.args[0:2]
  370. def _eval_rewrite_as_Piecewise(self, *args, **kwargs):
  371. from sympy.functions.elementary.piecewise import Piecewise
  372. i, j = args
  373. return Piecewise((0, Ne(i, j)), (1, True))