secondquant.py 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136
  1. """
  2. Second quantization operators and states for bosons.
  3. This follow the formulation of Fetter and Welecka, "Quantum Theory
  4. of Many-Particle Systems."
  5. """
  6. from collections import defaultdict
  7. from sympy.core.add import Add
  8. from sympy.core.basic import Basic
  9. from sympy.core.cache import cacheit
  10. from sympy.core.containers import Tuple
  11. from sympy.core.expr import Expr
  12. from sympy.core.function import Function
  13. from sympy.core.mul import Mul
  14. from sympy.core.numbers import I
  15. from sympy.core.power import Pow
  16. from sympy.core.singleton import S
  17. from sympy.core.sorting import default_sort_key
  18. from sympy.core.symbol import Dummy, Symbol
  19. from sympy.core.sympify import sympify
  20. from sympy.functions.elementary.miscellaneous import sqrt
  21. from sympy.functions.special.tensor_functions import KroneckerDelta
  22. from sympy.matrices.dense import zeros
  23. from sympy.printing.str import StrPrinter
  24. from sympy.utilities.iterables import has_dups
  25. __all__ = [
  26. 'Dagger',
  27. 'KroneckerDelta',
  28. 'BosonicOperator',
  29. 'AnnihilateBoson',
  30. 'CreateBoson',
  31. 'AnnihilateFermion',
  32. 'CreateFermion',
  33. 'FockState',
  34. 'FockStateBra',
  35. 'FockStateKet',
  36. 'FockStateBosonKet',
  37. 'FockStateBosonBra',
  38. 'FockStateFermionKet',
  39. 'FockStateFermionBra',
  40. 'BBra',
  41. 'BKet',
  42. 'FBra',
  43. 'FKet',
  44. 'F',
  45. 'Fd',
  46. 'B',
  47. 'Bd',
  48. 'apply_operators',
  49. 'InnerProduct',
  50. 'BosonicBasis',
  51. 'VarBosonicBasis',
  52. 'FixedBosonicBasis',
  53. 'Commutator',
  54. 'matrix_rep',
  55. 'contraction',
  56. 'wicks',
  57. 'NO',
  58. 'evaluate_deltas',
  59. 'AntiSymmetricTensor',
  60. 'substitute_dummies',
  61. 'PermutationOperator',
  62. 'simplify_index_permutations',
  63. ]
  64. class SecondQuantizationError(Exception):
  65. pass
  66. class AppliesOnlyToSymbolicIndex(SecondQuantizationError):
  67. pass
  68. class ContractionAppliesOnlyToFermions(SecondQuantizationError):
  69. pass
  70. class ViolationOfPauliPrinciple(SecondQuantizationError):
  71. pass
  72. class SubstitutionOfAmbigousOperatorFailed(SecondQuantizationError):
  73. pass
  74. class WicksTheoremDoesNotApply(SecondQuantizationError):
  75. pass
  76. class Dagger(Expr):
  77. """
  78. Hermitian conjugate of creation/annihilation operators.
  79. Examples
  80. ========
  81. >>> from sympy import I
  82. >>> from sympy.physics.secondquant import Dagger, B, Bd
  83. >>> Dagger(2*I)
  84. -2*I
  85. >>> Dagger(B(0))
  86. CreateBoson(0)
  87. >>> Dagger(Bd(0))
  88. AnnihilateBoson(0)
  89. """
  90. def __new__(cls, arg):
  91. arg = sympify(arg)
  92. r = cls.eval(arg)
  93. if isinstance(r, Basic):
  94. return r
  95. obj = Basic.__new__(cls, arg)
  96. return obj
  97. @classmethod
  98. def eval(cls, arg):
  99. """
  100. Evaluates the Dagger instance.
  101. Examples
  102. ========
  103. >>> from sympy import I
  104. >>> from sympy.physics.secondquant import Dagger, B, Bd
  105. >>> Dagger(2*I)
  106. -2*I
  107. >>> Dagger(B(0))
  108. CreateBoson(0)
  109. >>> Dagger(Bd(0))
  110. AnnihilateBoson(0)
  111. The eval() method is called automatically.
  112. """
  113. dagger = getattr(arg, '_dagger_', None)
  114. if dagger is not None:
  115. return dagger()
  116. if isinstance(arg, Basic):
  117. if arg.is_Add:
  118. return Add(*tuple(map(Dagger, arg.args)))
  119. if arg.is_Mul:
  120. return Mul(*tuple(map(Dagger, reversed(arg.args))))
  121. if arg.is_Number:
  122. return arg
  123. if arg.is_Pow:
  124. return Pow(Dagger(arg.args[0]), arg.args[1])
  125. if arg == I:
  126. return -arg
  127. else:
  128. return None
  129. def _dagger_(self):
  130. return self.args[0]
  131. class TensorSymbol(Expr):
  132. is_commutative = True
  133. class AntiSymmetricTensor(TensorSymbol):
  134. """Stores upper and lower indices in separate Tuple's.
  135. Each group of indices is assumed to be antisymmetric.
  136. Examples
  137. ========
  138. >>> from sympy import symbols
  139. >>> from sympy.physics.secondquant import AntiSymmetricTensor
  140. >>> i, j = symbols('i j', below_fermi=True)
  141. >>> a, b = symbols('a b', above_fermi=True)
  142. >>> AntiSymmetricTensor('v', (a, i), (b, j))
  143. AntiSymmetricTensor(v, (a, i), (b, j))
  144. >>> AntiSymmetricTensor('v', (i, a), (b, j))
  145. -AntiSymmetricTensor(v, (a, i), (b, j))
  146. As you can see, the indices are automatically sorted to a canonical form.
  147. """
  148. def __new__(cls, symbol, upper, lower):
  149. try:
  150. upper, signu = _sort_anticommuting_fermions(
  151. upper, key=cls._sortkey)
  152. lower, signl = _sort_anticommuting_fermions(
  153. lower, key=cls._sortkey)
  154. except ViolationOfPauliPrinciple:
  155. return S.Zero
  156. symbol = sympify(symbol)
  157. upper = Tuple(*upper)
  158. lower = Tuple(*lower)
  159. if (signu + signl) % 2:
  160. return -TensorSymbol.__new__(cls, symbol, upper, lower)
  161. else:
  162. return TensorSymbol.__new__(cls, symbol, upper, lower)
  163. @classmethod
  164. def _sortkey(cls, index):
  165. """Key for sorting of indices.
  166. particle < hole < general
  167. FIXME: This is a bottle-neck, can we do it faster?
  168. """
  169. h = hash(index)
  170. label = str(index)
  171. if isinstance(index, Dummy):
  172. if index.assumptions0.get('above_fermi'):
  173. return (20, label, h)
  174. elif index.assumptions0.get('below_fermi'):
  175. return (21, label, h)
  176. else:
  177. return (22, label, h)
  178. if index.assumptions0.get('above_fermi'):
  179. return (10, label, h)
  180. elif index.assumptions0.get('below_fermi'):
  181. return (11, label, h)
  182. else:
  183. return (12, label, h)
  184. def _latex(self, printer):
  185. return "{%s^{%s}_{%s}}" % (
  186. self.symbol,
  187. "".join([ i.name for i in self.args[1]]),
  188. "".join([ i.name for i in self.args[2]])
  189. )
  190. @property
  191. def symbol(self):
  192. """
  193. Returns the symbol of the tensor.
  194. Examples
  195. ========
  196. >>> from sympy import symbols
  197. >>> from sympy.physics.secondquant import AntiSymmetricTensor
  198. >>> i, j = symbols('i,j', below_fermi=True)
  199. >>> a, b = symbols('a,b', above_fermi=True)
  200. >>> AntiSymmetricTensor('v', (a, i), (b, j))
  201. AntiSymmetricTensor(v, (a, i), (b, j))
  202. >>> AntiSymmetricTensor('v', (a, i), (b, j)).symbol
  203. v
  204. """
  205. return self.args[0]
  206. @property
  207. def upper(self):
  208. """
  209. Returns the upper indices.
  210. Examples
  211. ========
  212. >>> from sympy import symbols
  213. >>> from sympy.physics.secondquant import AntiSymmetricTensor
  214. >>> i, j = symbols('i,j', below_fermi=True)
  215. >>> a, b = symbols('a,b', above_fermi=True)
  216. >>> AntiSymmetricTensor('v', (a, i), (b, j))
  217. AntiSymmetricTensor(v, (a, i), (b, j))
  218. >>> AntiSymmetricTensor('v', (a, i), (b, j)).upper
  219. (a, i)
  220. """
  221. return self.args[1]
  222. @property
  223. def lower(self):
  224. """
  225. Returns the lower indices.
  226. Examples
  227. ========
  228. >>> from sympy import symbols
  229. >>> from sympy.physics.secondquant import AntiSymmetricTensor
  230. >>> i, j = symbols('i,j', below_fermi=True)
  231. >>> a, b = symbols('a,b', above_fermi=True)
  232. >>> AntiSymmetricTensor('v', (a, i), (b, j))
  233. AntiSymmetricTensor(v, (a, i), (b, j))
  234. >>> AntiSymmetricTensor('v', (a, i), (b, j)).lower
  235. (b, j)
  236. """
  237. return self.args[2]
  238. def __str__(self):
  239. return "%s(%s,%s)" % self.args
  240. def doit(self, **kw_args):
  241. """
  242. Returns self.
  243. Examples
  244. ========
  245. >>> from sympy import symbols
  246. >>> from sympy.physics.secondquant import AntiSymmetricTensor
  247. >>> i, j = symbols('i,j', below_fermi=True)
  248. >>> a, b = symbols('a,b', above_fermi=True)
  249. >>> AntiSymmetricTensor('v', (a, i), (b, j)).doit()
  250. AntiSymmetricTensor(v, (a, i), (b, j))
  251. """
  252. return self
  253. class SqOperator(Expr):
  254. """
  255. Base class for Second Quantization operators.
  256. """
  257. op_symbol = 'sq'
  258. is_commutative = False
  259. def __new__(cls, k):
  260. obj = Basic.__new__(cls, sympify(k))
  261. return obj
  262. @property
  263. def state(self):
  264. """
  265. Returns the state index related to this operator.
  266. Examples
  267. ========
  268. >>> from sympy import Symbol
  269. >>> from sympy.physics.secondquant import F, Fd, B, Bd
  270. >>> p = Symbol('p')
  271. >>> F(p).state
  272. p
  273. >>> Fd(p).state
  274. p
  275. >>> B(p).state
  276. p
  277. >>> Bd(p).state
  278. p
  279. """
  280. return self.args[0]
  281. @property
  282. def is_symbolic(self):
  283. """
  284. Returns True if the state is a symbol (as opposed to a number).
  285. Examples
  286. ========
  287. >>> from sympy import Symbol
  288. >>> from sympy.physics.secondquant import F
  289. >>> p = Symbol('p')
  290. >>> F(p).is_symbolic
  291. True
  292. >>> F(1).is_symbolic
  293. False
  294. """
  295. if self.state.is_Integer:
  296. return False
  297. else:
  298. return True
  299. def doit(self, **kw_args):
  300. """
  301. FIXME: hack to prevent crash further up...
  302. """
  303. return self
  304. def __repr__(self):
  305. return NotImplemented
  306. def __str__(self):
  307. return "%s(%r)" % (self.op_symbol, self.state)
  308. def apply_operator(self, state):
  309. """
  310. Applies an operator to itself.
  311. """
  312. raise NotImplementedError('implement apply_operator in a subclass')
  313. class BosonicOperator(SqOperator):
  314. pass
  315. class Annihilator(SqOperator):
  316. pass
  317. class Creator(SqOperator):
  318. pass
  319. class AnnihilateBoson(BosonicOperator, Annihilator):
  320. """
  321. Bosonic annihilation operator.
  322. Examples
  323. ========
  324. >>> from sympy.physics.secondquant import B
  325. >>> from sympy.abc import x
  326. >>> B(x)
  327. AnnihilateBoson(x)
  328. """
  329. op_symbol = 'b'
  330. def _dagger_(self):
  331. return CreateBoson(self.state)
  332. def apply_operator(self, state):
  333. """
  334. Apply state to self if self is not symbolic and state is a FockStateKet, else
  335. multiply self by state.
  336. Examples
  337. ========
  338. >>> from sympy.physics.secondquant import B, BKet
  339. >>> from sympy.abc import x, y, n
  340. >>> B(x).apply_operator(y)
  341. y*AnnihilateBoson(x)
  342. >>> B(0).apply_operator(BKet((n,)))
  343. sqrt(n)*FockStateBosonKet((n - 1,))
  344. """
  345. if not self.is_symbolic and isinstance(state, FockStateKet):
  346. element = self.state
  347. amp = sqrt(state[element])
  348. return amp*state.down(element)
  349. else:
  350. return Mul(self, state)
  351. def __repr__(self):
  352. return "AnnihilateBoson(%s)" % self.state
  353. def _latex(self, printer):
  354. if self.state is S.Zero:
  355. return "b_{0}"
  356. else:
  357. return "b_{%s}" % self.state.name
  358. class CreateBoson(BosonicOperator, Creator):
  359. """
  360. Bosonic creation operator.
  361. """
  362. op_symbol = 'b+'
  363. def _dagger_(self):
  364. return AnnihilateBoson(self.state)
  365. def apply_operator(self, state):
  366. """
  367. Apply state to self if self is not symbolic and state is a FockStateKet, else
  368. multiply self by state.
  369. Examples
  370. ========
  371. >>> from sympy.physics.secondquant import B, Dagger, BKet
  372. >>> from sympy.abc import x, y, n
  373. >>> Dagger(B(x)).apply_operator(y)
  374. y*CreateBoson(x)
  375. >>> B(0).apply_operator(BKet((n,)))
  376. sqrt(n)*FockStateBosonKet((n - 1,))
  377. """
  378. if not self.is_symbolic and isinstance(state, FockStateKet):
  379. element = self.state
  380. amp = sqrt(state[element] + 1)
  381. return amp*state.up(element)
  382. else:
  383. return Mul(self, state)
  384. def __repr__(self):
  385. return "CreateBoson(%s)" % self.state
  386. def _latex(self, printer):
  387. if self.state is S.Zero:
  388. return "{b^\\dagger_{0}}"
  389. else:
  390. return "{b^\\dagger_{%s}}" % self.state.name
  391. B = AnnihilateBoson
  392. Bd = CreateBoson
  393. class FermionicOperator(SqOperator):
  394. @property
  395. def is_restricted(self):
  396. """
  397. Is this FermionicOperator restricted with respect to fermi level?
  398. Returns
  399. =======
  400. 1 : restricted to orbits above fermi
  401. 0 : no restriction
  402. -1 : restricted to orbits below fermi
  403. Examples
  404. ========
  405. >>> from sympy import Symbol
  406. >>> from sympy.physics.secondquant import F, Fd
  407. >>> a = Symbol('a', above_fermi=True)
  408. >>> i = Symbol('i', below_fermi=True)
  409. >>> p = Symbol('p')
  410. >>> F(a).is_restricted
  411. 1
  412. >>> Fd(a).is_restricted
  413. 1
  414. >>> F(i).is_restricted
  415. -1
  416. >>> Fd(i).is_restricted
  417. -1
  418. >>> F(p).is_restricted
  419. 0
  420. >>> Fd(p).is_restricted
  421. 0
  422. """
  423. ass = self.args[0].assumptions0
  424. if ass.get("below_fermi"):
  425. return -1
  426. if ass.get("above_fermi"):
  427. return 1
  428. return 0
  429. @property
  430. def is_above_fermi(self):
  431. """
  432. Does the index of this FermionicOperator allow values above fermi?
  433. Examples
  434. ========
  435. >>> from sympy import Symbol
  436. >>> from sympy.physics.secondquant import F
  437. >>> a = Symbol('a', above_fermi=True)
  438. >>> i = Symbol('i', below_fermi=True)
  439. >>> p = Symbol('p')
  440. >>> F(a).is_above_fermi
  441. True
  442. >>> F(i).is_above_fermi
  443. False
  444. >>> F(p).is_above_fermi
  445. True
  446. Note
  447. ====
  448. The same applies to creation operators Fd
  449. """
  450. return not self.args[0].assumptions0.get("below_fermi")
  451. @property
  452. def is_below_fermi(self):
  453. """
  454. Does the index of this FermionicOperator allow values below fermi?
  455. Examples
  456. ========
  457. >>> from sympy import Symbol
  458. >>> from sympy.physics.secondquant import F
  459. >>> a = Symbol('a', above_fermi=True)
  460. >>> i = Symbol('i', below_fermi=True)
  461. >>> p = Symbol('p')
  462. >>> F(a).is_below_fermi
  463. False
  464. >>> F(i).is_below_fermi
  465. True
  466. >>> F(p).is_below_fermi
  467. True
  468. The same applies to creation operators Fd
  469. """
  470. return not self.args[0].assumptions0.get("above_fermi")
  471. @property
  472. def is_only_below_fermi(self):
  473. """
  474. Is the index of this FermionicOperator restricted to values below fermi?
  475. Examples
  476. ========
  477. >>> from sympy import Symbol
  478. >>> from sympy.physics.secondquant import F
  479. >>> a = Symbol('a', above_fermi=True)
  480. >>> i = Symbol('i', below_fermi=True)
  481. >>> p = Symbol('p')
  482. >>> F(a).is_only_below_fermi
  483. False
  484. >>> F(i).is_only_below_fermi
  485. True
  486. >>> F(p).is_only_below_fermi
  487. False
  488. The same applies to creation operators Fd
  489. """
  490. return self.is_below_fermi and not self.is_above_fermi
  491. @property
  492. def is_only_above_fermi(self):
  493. """
  494. Is the index of this FermionicOperator restricted to values above fermi?
  495. Examples
  496. ========
  497. >>> from sympy import Symbol
  498. >>> from sympy.physics.secondquant import F
  499. >>> a = Symbol('a', above_fermi=True)
  500. >>> i = Symbol('i', below_fermi=True)
  501. >>> p = Symbol('p')
  502. >>> F(a).is_only_above_fermi
  503. True
  504. >>> F(i).is_only_above_fermi
  505. False
  506. >>> F(p).is_only_above_fermi
  507. False
  508. The same applies to creation operators Fd
  509. """
  510. return self.is_above_fermi and not self.is_below_fermi
  511. def _sortkey(self):
  512. h = hash(self)
  513. label = str(self.args[0])
  514. if self.is_only_q_creator:
  515. return 1, label, h
  516. if self.is_only_q_annihilator:
  517. return 4, label, h
  518. if isinstance(self, Annihilator):
  519. return 3, label, h
  520. if isinstance(self, Creator):
  521. return 2, label, h
  522. class AnnihilateFermion(FermionicOperator, Annihilator):
  523. """
  524. Fermionic annihilation operator.
  525. """
  526. op_symbol = 'f'
  527. def _dagger_(self):
  528. return CreateFermion(self.state)
  529. def apply_operator(self, state):
  530. """
  531. Apply state to self if self is not symbolic and state is a FockStateKet, else
  532. multiply self by state.
  533. Examples
  534. ========
  535. >>> from sympy.physics.secondquant import B, Dagger, BKet
  536. >>> from sympy.abc import x, y, n
  537. >>> Dagger(B(x)).apply_operator(y)
  538. y*CreateBoson(x)
  539. >>> B(0).apply_operator(BKet((n,)))
  540. sqrt(n)*FockStateBosonKet((n - 1,))
  541. """
  542. if isinstance(state, FockStateFermionKet):
  543. element = self.state
  544. return state.down(element)
  545. elif isinstance(state, Mul):
  546. c_part, nc_part = state.args_cnc()
  547. if isinstance(nc_part[0], FockStateFermionKet):
  548. element = self.state
  549. return Mul(*(c_part + [nc_part[0].down(element)] + nc_part[1:]))
  550. else:
  551. return Mul(self, state)
  552. else:
  553. return Mul(self, state)
  554. @property
  555. def is_q_creator(self):
  556. """
  557. Can we create a quasi-particle? (create hole or create particle)
  558. If so, would that be above or below the fermi surface?
  559. Examples
  560. ========
  561. >>> from sympy import Symbol
  562. >>> from sympy.physics.secondquant import F
  563. >>> a = Symbol('a', above_fermi=True)
  564. >>> i = Symbol('i', below_fermi=True)
  565. >>> p = Symbol('p')
  566. >>> F(a).is_q_creator
  567. 0
  568. >>> F(i).is_q_creator
  569. -1
  570. >>> F(p).is_q_creator
  571. -1
  572. """
  573. if self.is_below_fermi:
  574. return -1
  575. return 0
  576. @property
  577. def is_q_annihilator(self):
  578. """
  579. Can we destroy a quasi-particle? (annihilate hole or annihilate particle)
  580. If so, would that be above or below the fermi surface?
  581. Examples
  582. ========
  583. >>> from sympy import Symbol
  584. >>> from sympy.physics.secondquant import F
  585. >>> a = Symbol('a', above_fermi=1)
  586. >>> i = Symbol('i', below_fermi=1)
  587. >>> p = Symbol('p')
  588. >>> F(a).is_q_annihilator
  589. 1
  590. >>> F(i).is_q_annihilator
  591. 0
  592. >>> F(p).is_q_annihilator
  593. 1
  594. """
  595. if self.is_above_fermi:
  596. return 1
  597. return 0
  598. @property
  599. def is_only_q_creator(self):
  600. """
  601. Always create a quasi-particle? (create hole or create particle)
  602. Examples
  603. ========
  604. >>> from sympy import Symbol
  605. >>> from sympy.physics.secondquant import F
  606. >>> a = Symbol('a', above_fermi=True)
  607. >>> i = Symbol('i', below_fermi=True)
  608. >>> p = Symbol('p')
  609. >>> F(a).is_only_q_creator
  610. False
  611. >>> F(i).is_only_q_creator
  612. True
  613. >>> F(p).is_only_q_creator
  614. False
  615. """
  616. return self.is_only_below_fermi
  617. @property
  618. def is_only_q_annihilator(self):
  619. """
  620. Always destroy a quasi-particle? (annihilate hole or annihilate particle)
  621. Examples
  622. ========
  623. >>> from sympy import Symbol
  624. >>> from sympy.physics.secondquant import F
  625. >>> a = Symbol('a', above_fermi=True)
  626. >>> i = Symbol('i', below_fermi=True)
  627. >>> p = Symbol('p')
  628. >>> F(a).is_only_q_annihilator
  629. True
  630. >>> F(i).is_only_q_annihilator
  631. False
  632. >>> F(p).is_only_q_annihilator
  633. False
  634. """
  635. return self.is_only_above_fermi
  636. def __repr__(self):
  637. return "AnnihilateFermion(%s)" % self.state
  638. def _latex(self, printer):
  639. if self.state is S.Zero:
  640. return "a_{0}"
  641. else:
  642. return "a_{%s}" % self.state.name
  643. class CreateFermion(FermionicOperator, Creator):
  644. """
  645. Fermionic creation operator.
  646. """
  647. op_symbol = 'f+'
  648. def _dagger_(self):
  649. return AnnihilateFermion(self.state)
  650. def apply_operator(self, state):
  651. """
  652. Apply state to self if self is not symbolic and state is a FockStateKet, else
  653. multiply self by state.
  654. Examples
  655. ========
  656. >>> from sympy.physics.secondquant import B, Dagger, BKet
  657. >>> from sympy.abc import x, y, n
  658. >>> Dagger(B(x)).apply_operator(y)
  659. y*CreateBoson(x)
  660. >>> B(0).apply_operator(BKet((n,)))
  661. sqrt(n)*FockStateBosonKet((n - 1,))
  662. """
  663. if isinstance(state, FockStateFermionKet):
  664. element = self.state
  665. return state.up(element)
  666. elif isinstance(state, Mul):
  667. c_part, nc_part = state.args_cnc()
  668. if isinstance(nc_part[0], FockStateFermionKet):
  669. element = self.state
  670. return Mul(*(c_part + [nc_part[0].up(element)] + nc_part[1:]))
  671. return Mul(self, state)
  672. @property
  673. def is_q_creator(self):
  674. """
  675. Can we create a quasi-particle? (create hole or create particle)
  676. If so, would that be above or below the fermi surface?
  677. Examples
  678. ========
  679. >>> from sympy import Symbol
  680. >>> from sympy.physics.secondquant import Fd
  681. >>> a = Symbol('a', above_fermi=True)
  682. >>> i = Symbol('i', below_fermi=True)
  683. >>> p = Symbol('p')
  684. >>> Fd(a).is_q_creator
  685. 1
  686. >>> Fd(i).is_q_creator
  687. 0
  688. >>> Fd(p).is_q_creator
  689. 1
  690. """
  691. if self.is_above_fermi:
  692. return 1
  693. return 0
  694. @property
  695. def is_q_annihilator(self):
  696. """
  697. Can we destroy a quasi-particle? (annihilate hole or annihilate particle)
  698. If so, would that be above or below the fermi surface?
  699. Examples
  700. ========
  701. >>> from sympy import Symbol
  702. >>> from sympy.physics.secondquant import Fd
  703. >>> a = Symbol('a', above_fermi=1)
  704. >>> i = Symbol('i', below_fermi=1)
  705. >>> p = Symbol('p')
  706. >>> Fd(a).is_q_annihilator
  707. 0
  708. >>> Fd(i).is_q_annihilator
  709. -1
  710. >>> Fd(p).is_q_annihilator
  711. -1
  712. """
  713. if self.is_below_fermi:
  714. return -1
  715. return 0
  716. @property
  717. def is_only_q_creator(self):
  718. """
  719. Always create a quasi-particle? (create hole or create particle)
  720. Examples
  721. ========
  722. >>> from sympy import Symbol
  723. >>> from sympy.physics.secondquant import Fd
  724. >>> a = Symbol('a', above_fermi=True)
  725. >>> i = Symbol('i', below_fermi=True)
  726. >>> p = Symbol('p')
  727. >>> Fd(a).is_only_q_creator
  728. True
  729. >>> Fd(i).is_only_q_creator
  730. False
  731. >>> Fd(p).is_only_q_creator
  732. False
  733. """
  734. return self.is_only_above_fermi
  735. @property
  736. def is_only_q_annihilator(self):
  737. """
  738. Always destroy a quasi-particle? (annihilate hole or annihilate particle)
  739. Examples
  740. ========
  741. >>> from sympy import Symbol
  742. >>> from sympy.physics.secondquant import Fd
  743. >>> a = Symbol('a', above_fermi=True)
  744. >>> i = Symbol('i', below_fermi=True)
  745. >>> p = Symbol('p')
  746. >>> Fd(a).is_only_q_annihilator
  747. False
  748. >>> Fd(i).is_only_q_annihilator
  749. True
  750. >>> Fd(p).is_only_q_annihilator
  751. False
  752. """
  753. return self.is_only_below_fermi
  754. def __repr__(self):
  755. return "CreateFermion(%s)" % self.state
  756. def _latex(self, printer):
  757. if self.state is S.Zero:
  758. return "{a^\\dagger_{0}}"
  759. else:
  760. return "{a^\\dagger_{%s}}" % self.state.name
  761. Fd = CreateFermion
  762. F = AnnihilateFermion
  763. class FockState(Expr):
  764. """
  765. Many particle Fock state with a sequence of occupation numbers.
  766. Anywhere you can have a FockState, you can also have S.Zero.
  767. All code must check for this!
  768. Base class to represent FockStates.
  769. """
  770. is_commutative = False
  771. def __new__(cls, occupations):
  772. """
  773. occupations is a list with two possible meanings:
  774. - For bosons it is a list of occupation numbers.
  775. Element i is the number of particles in state i.
  776. - For fermions it is a list of occupied orbits.
  777. Element 0 is the state that was occupied first, element i
  778. is the i'th occupied state.
  779. """
  780. occupations = list(map(sympify, occupations))
  781. obj = Basic.__new__(cls, Tuple(*occupations))
  782. return obj
  783. def __getitem__(self, i):
  784. i = int(i)
  785. return self.args[0][i]
  786. def __repr__(self):
  787. return ("FockState(%r)") % (self.args)
  788. def __str__(self):
  789. return "%s%r%s" % (getattr(self, 'lbracket', ""), self._labels(), getattr(self, 'rbracket', ""))
  790. def _labels(self):
  791. return self.args[0]
  792. def __len__(self):
  793. return len(self.args[0])
  794. def _latex(self, printer):
  795. return "%s%s%s" % (getattr(self, 'lbracket_latex', ""), printer._print(self._labels()), getattr(self, 'rbracket_latex', ""))
  796. class BosonState(FockState):
  797. """
  798. Base class for FockStateBoson(Ket/Bra).
  799. """
  800. def up(self, i):
  801. """
  802. Performs the action of a creation operator.
  803. Examples
  804. ========
  805. >>> from sympy.physics.secondquant import BBra
  806. >>> b = BBra([1, 2])
  807. >>> b
  808. FockStateBosonBra((1, 2))
  809. >>> b.up(1)
  810. FockStateBosonBra((1, 3))
  811. """
  812. i = int(i)
  813. new_occs = list(self.args[0])
  814. new_occs[i] = new_occs[i] + S.One
  815. return self.__class__(new_occs)
  816. def down(self, i):
  817. """
  818. Performs the action of an annihilation operator.
  819. Examples
  820. ========
  821. >>> from sympy.physics.secondquant import BBra
  822. >>> b = BBra([1, 2])
  823. >>> b
  824. FockStateBosonBra((1, 2))
  825. >>> b.down(1)
  826. FockStateBosonBra((1, 1))
  827. """
  828. i = int(i)
  829. new_occs = list(self.args[0])
  830. if new_occs[i] == S.Zero:
  831. return S.Zero
  832. else:
  833. new_occs[i] = new_occs[i] - S.One
  834. return self.__class__(new_occs)
  835. class FermionState(FockState):
  836. """
  837. Base class for FockStateFermion(Ket/Bra).
  838. """
  839. fermi_level = 0
  840. def __new__(cls, occupations, fermi_level=0):
  841. occupations = list(map(sympify, occupations))
  842. if len(occupations) > 1:
  843. try:
  844. (occupations, sign) = _sort_anticommuting_fermions(
  845. occupations, key=hash)
  846. except ViolationOfPauliPrinciple:
  847. return S.Zero
  848. else:
  849. sign = 0
  850. cls.fermi_level = fermi_level
  851. if cls._count_holes(occupations) > fermi_level:
  852. return S.Zero
  853. if sign % 2:
  854. return S.NegativeOne*FockState.__new__(cls, occupations)
  855. else:
  856. return FockState.__new__(cls, occupations)
  857. def up(self, i):
  858. """
  859. Performs the action of a creation operator.
  860. Explanation
  861. ===========
  862. If below fermi we try to remove a hole,
  863. if above fermi we try to create a particle.
  864. If general index p we return ``Kronecker(p,i)*self``
  865. where ``i`` is a new symbol with restriction above or below.
  866. Examples
  867. ========
  868. >>> from sympy import Symbol
  869. >>> from sympy.physics.secondquant import FKet
  870. >>> a = Symbol('a', above_fermi=True)
  871. >>> i = Symbol('i', below_fermi=True)
  872. >>> p = Symbol('p')
  873. >>> FKet([]).up(a)
  874. FockStateFermionKet((a,))
  875. A creator acting on vacuum below fermi vanishes
  876. >>> FKet([]).up(i)
  877. 0
  878. """
  879. present = i in self.args[0]
  880. if self._only_above_fermi(i):
  881. if present:
  882. return S.Zero
  883. else:
  884. return self._add_orbit(i)
  885. elif self._only_below_fermi(i):
  886. if present:
  887. return self._remove_orbit(i)
  888. else:
  889. return S.Zero
  890. else:
  891. if present:
  892. hole = Dummy("i", below_fermi=True)
  893. return KroneckerDelta(i, hole)*self._remove_orbit(i)
  894. else:
  895. particle = Dummy("a", above_fermi=True)
  896. return KroneckerDelta(i, particle)*self._add_orbit(i)
  897. def down(self, i):
  898. """
  899. Performs the action of an annihilation operator.
  900. Explanation
  901. ===========
  902. If below fermi we try to create a hole,
  903. If above fermi we try to remove a particle.
  904. If general index p we return ``Kronecker(p,i)*self``
  905. where ``i`` is a new symbol with restriction above or below.
  906. Examples
  907. ========
  908. >>> from sympy import Symbol
  909. >>> from sympy.physics.secondquant import FKet
  910. >>> a = Symbol('a', above_fermi=True)
  911. >>> i = Symbol('i', below_fermi=True)
  912. >>> p = Symbol('p')
  913. An annihilator acting on vacuum above fermi vanishes
  914. >>> FKet([]).down(a)
  915. 0
  916. Also below fermi, it vanishes, unless we specify a fermi level > 0
  917. >>> FKet([]).down(i)
  918. 0
  919. >>> FKet([],4).down(i)
  920. FockStateFermionKet((i,))
  921. """
  922. present = i in self.args[0]
  923. if self._only_above_fermi(i):
  924. if present:
  925. return self._remove_orbit(i)
  926. else:
  927. return S.Zero
  928. elif self._only_below_fermi(i):
  929. if present:
  930. return S.Zero
  931. else:
  932. return self._add_orbit(i)
  933. else:
  934. if present:
  935. hole = Dummy("i", below_fermi=True)
  936. return KroneckerDelta(i, hole)*self._add_orbit(i)
  937. else:
  938. particle = Dummy("a", above_fermi=True)
  939. return KroneckerDelta(i, particle)*self._remove_orbit(i)
  940. @classmethod
  941. def _only_below_fermi(cls, i):
  942. """
  943. Tests if given orbit is only below fermi surface.
  944. If nothing can be concluded we return a conservative False.
  945. """
  946. if i.is_number:
  947. return i <= cls.fermi_level
  948. if i.assumptions0.get('below_fermi'):
  949. return True
  950. return False
  951. @classmethod
  952. def _only_above_fermi(cls, i):
  953. """
  954. Tests if given orbit is only above fermi surface.
  955. If fermi level has not been set we return True.
  956. If nothing can be concluded we return a conservative False.
  957. """
  958. if i.is_number:
  959. return i > cls.fermi_level
  960. if i.assumptions0.get('above_fermi'):
  961. return True
  962. return not cls.fermi_level
  963. def _remove_orbit(self, i):
  964. """
  965. Removes particle/fills hole in orbit i. No input tests performed here.
  966. """
  967. new_occs = list(self.args[0])
  968. pos = new_occs.index(i)
  969. del new_occs[pos]
  970. if (pos) % 2:
  971. return S.NegativeOne*self.__class__(new_occs, self.fermi_level)
  972. else:
  973. return self.__class__(new_occs, self.fermi_level)
  974. def _add_orbit(self, i):
  975. """
  976. Adds particle/creates hole in orbit i. No input tests performed here.
  977. """
  978. return self.__class__((i,) + self.args[0], self.fermi_level)
  979. @classmethod
  980. def _count_holes(cls, list):
  981. """
  982. Returns the number of identified hole states in list.
  983. """
  984. return len([i for i in list if cls._only_below_fermi(i)])
  985. def _negate_holes(self, list):
  986. return tuple([-i if i <= self.fermi_level else i for i in list])
  987. def __repr__(self):
  988. if self.fermi_level:
  989. return "FockStateKet(%r, fermi_level=%s)" % (self.args[0], self.fermi_level)
  990. else:
  991. return "FockStateKet(%r)" % (self.args[0],)
  992. def _labels(self):
  993. return self._negate_holes(self.args[0])
  994. class FockStateKet(FockState):
  995. """
  996. Representation of a ket.
  997. """
  998. lbracket = '|'
  999. rbracket = '>'
  1000. lbracket_latex = r'\left|'
  1001. rbracket_latex = r'\right\rangle'
  1002. class FockStateBra(FockState):
  1003. """
  1004. Representation of a bra.
  1005. """
  1006. lbracket = '<'
  1007. rbracket = '|'
  1008. lbracket_latex = r'\left\langle'
  1009. rbracket_latex = r'\right|'
  1010. def __mul__(self, other):
  1011. if isinstance(other, FockStateKet):
  1012. return InnerProduct(self, other)
  1013. else:
  1014. return Expr.__mul__(self, other)
  1015. class FockStateBosonKet(BosonState, FockStateKet):
  1016. """
  1017. Many particle Fock state with a sequence of occupation numbers.
  1018. Occupation numbers can be any integer >= 0.
  1019. Examples
  1020. ========
  1021. >>> from sympy.physics.secondquant import BKet
  1022. >>> BKet([1, 2])
  1023. FockStateBosonKet((1, 2))
  1024. """
  1025. def _dagger_(self):
  1026. return FockStateBosonBra(*self.args)
  1027. class FockStateBosonBra(BosonState, FockStateBra):
  1028. """
  1029. Describes a collection of BosonBra particles.
  1030. Examples
  1031. ========
  1032. >>> from sympy.physics.secondquant import BBra
  1033. >>> BBra([1, 2])
  1034. FockStateBosonBra((1, 2))
  1035. """
  1036. def _dagger_(self):
  1037. return FockStateBosonKet(*self.args)
  1038. class FockStateFermionKet(FermionState, FockStateKet):
  1039. """
  1040. Many-particle Fock state with a sequence of occupied orbits.
  1041. Explanation
  1042. ===========
  1043. Each state can only have one particle, so we choose to store a list of
  1044. occupied orbits rather than a tuple with occupation numbers (zeros and ones).
  1045. states below fermi level are holes, and are represented by negative labels
  1046. in the occupation list.
  1047. For symbolic state labels, the fermi_level caps the number of allowed hole-
  1048. states.
  1049. Examples
  1050. ========
  1051. >>> from sympy.physics.secondquant import FKet
  1052. >>> FKet([1, 2])
  1053. FockStateFermionKet((1, 2))
  1054. """
  1055. def _dagger_(self):
  1056. return FockStateFermionBra(*self.args)
  1057. class FockStateFermionBra(FermionState, FockStateBra):
  1058. """
  1059. See Also
  1060. ========
  1061. FockStateFermionKet
  1062. Examples
  1063. ========
  1064. >>> from sympy.physics.secondquant import FBra
  1065. >>> FBra([1, 2])
  1066. FockStateFermionBra((1, 2))
  1067. """
  1068. def _dagger_(self):
  1069. return FockStateFermionKet(*self.args)
  1070. BBra = FockStateBosonBra
  1071. BKet = FockStateBosonKet
  1072. FBra = FockStateFermionBra
  1073. FKet = FockStateFermionKet
  1074. def _apply_Mul(m):
  1075. """
  1076. Take a Mul instance with operators and apply them to states.
  1077. Explanation
  1078. ===========
  1079. This method applies all operators with integer state labels
  1080. to the actual states. For symbolic state labels, nothing is done.
  1081. When inner products of FockStates are encountered (like <a|b>),
  1082. they are converted to instances of InnerProduct.
  1083. This does not currently work on double inner products like,
  1084. <a|b><c|d>.
  1085. If the argument is not a Mul, it is simply returned as is.
  1086. """
  1087. if not isinstance(m, Mul):
  1088. return m
  1089. c_part, nc_part = m.args_cnc()
  1090. n_nc = len(nc_part)
  1091. if n_nc in (0, 1):
  1092. return m
  1093. else:
  1094. last = nc_part[-1]
  1095. next_to_last = nc_part[-2]
  1096. if isinstance(last, FockStateKet):
  1097. if isinstance(next_to_last, SqOperator):
  1098. if next_to_last.is_symbolic:
  1099. return m
  1100. else:
  1101. result = next_to_last.apply_operator(last)
  1102. if result == 0:
  1103. return S.Zero
  1104. else:
  1105. return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result])))
  1106. elif isinstance(next_to_last, Pow):
  1107. if isinstance(next_to_last.base, SqOperator) and \
  1108. next_to_last.exp.is_Integer:
  1109. if next_to_last.base.is_symbolic:
  1110. return m
  1111. else:
  1112. result = last
  1113. for i in range(next_to_last.exp):
  1114. result = next_to_last.base.apply_operator(result)
  1115. if result == 0:
  1116. break
  1117. if result == 0:
  1118. return S.Zero
  1119. else:
  1120. return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result])))
  1121. else:
  1122. return m
  1123. elif isinstance(next_to_last, FockStateBra):
  1124. result = InnerProduct(next_to_last, last)
  1125. if result == 0:
  1126. return S.Zero
  1127. else:
  1128. return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result])))
  1129. else:
  1130. return m
  1131. else:
  1132. return m
  1133. def apply_operators(e):
  1134. """
  1135. Take a SymPy expression with operators and states and apply the operators.
  1136. Examples
  1137. ========
  1138. >>> from sympy.physics.secondquant import apply_operators
  1139. >>> from sympy import sympify
  1140. >>> apply_operators(sympify(3)+4)
  1141. 7
  1142. """
  1143. e = e.expand()
  1144. muls = e.atoms(Mul)
  1145. subs_list = [(m, _apply_Mul(m)) for m in iter(muls)]
  1146. return e.subs(subs_list)
  1147. class InnerProduct(Basic):
  1148. """
  1149. An unevaluated inner product between a bra and ket.
  1150. Explanation
  1151. ===========
  1152. Currently this class just reduces things to a product of
  1153. Kronecker Deltas. In the future, we could introduce abstract
  1154. states like ``|a>`` and ``|b>``, and leave the inner product unevaluated as
  1155. ``<a|b>``.
  1156. """
  1157. is_commutative = True
  1158. def __new__(cls, bra, ket):
  1159. if not isinstance(bra, FockStateBra):
  1160. raise TypeError("must be a bra")
  1161. if not isinstance(ket, FockStateKet):
  1162. raise TypeError("must be a key")
  1163. return cls.eval(bra, ket)
  1164. @classmethod
  1165. def eval(cls, bra, ket):
  1166. result = S.One
  1167. for i, j in zip(bra.args[0], ket.args[0]):
  1168. result *= KroneckerDelta(i, j)
  1169. if result == 0:
  1170. break
  1171. return result
  1172. @property
  1173. def bra(self):
  1174. """Returns the bra part of the state"""
  1175. return self.args[0]
  1176. @property
  1177. def ket(self):
  1178. """Returns the ket part of the state"""
  1179. return self.args[1]
  1180. def __repr__(self):
  1181. sbra = repr(self.bra)
  1182. sket = repr(self.ket)
  1183. return "%s|%s" % (sbra[:-1], sket[1:])
  1184. def __str__(self):
  1185. return self.__repr__()
  1186. def matrix_rep(op, basis):
  1187. """
  1188. Find the representation of an operator in a basis.
  1189. Examples
  1190. ========
  1191. >>> from sympy.physics.secondquant import VarBosonicBasis, B, matrix_rep
  1192. >>> b = VarBosonicBasis(5)
  1193. >>> o = B(0)
  1194. >>> matrix_rep(o, b)
  1195. Matrix([
  1196. [0, 1, 0, 0, 0],
  1197. [0, 0, sqrt(2), 0, 0],
  1198. [0, 0, 0, sqrt(3), 0],
  1199. [0, 0, 0, 0, 2],
  1200. [0, 0, 0, 0, 0]])
  1201. """
  1202. a = zeros(len(basis))
  1203. for i in range(len(basis)):
  1204. for j in range(len(basis)):
  1205. a[i, j] = apply_operators(Dagger(basis[i])*op*basis[j])
  1206. return a
  1207. class BosonicBasis:
  1208. """
  1209. Base class for a basis set of bosonic Fock states.
  1210. """
  1211. pass
  1212. class VarBosonicBasis:
  1213. """
  1214. A single state, variable particle number basis set.
  1215. Examples
  1216. ========
  1217. >>> from sympy.physics.secondquant import VarBosonicBasis
  1218. >>> b = VarBosonicBasis(5)
  1219. >>> b
  1220. [FockState((0,)), FockState((1,)), FockState((2,)),
  1221. FockState((3,)), FockState((4,))]
  1222. """
  1223. def __init__(self, n_max):
  1224. self.n_max = n_max
  1225. self._build_states()
  1226. def _build_states(self):
  1227. self.basis = []
  1228. for i in range(self.n_max):
  1229. self.basis.append(FockStateBosonKet([i]))
  1230. self.n_basis = len(self.basis)
  1231. def index(self, state):
  1232. """
  1233. Returns the index of state in basis.
  1234. Examples
  1235. ========
  1236. >>> from sympy.physics.secondquant import VarBosonicBasis
  1237. >>> b = VarBosonicBasis(3)
  1238. >>> state = b.state(1)
  1239. >>> b
  1240. [FockState((0,)), FockState((1,)), FockState((2,))]
  1241. >>> state
  1242. FockStateBosonKet((1,))
  1243. >>> b.index(state)
  1244. 1
  1245. """
  1246. return self.basis.index(state)
  1247. def state(self, i):
  1248. """
  1249. The state of a single basis.
  1250. Examples
  1251. ========
  1252. >>> from sympy.physics.secondquant import VarBosonicBasis
  1253. >>> b = VarBosonicBasis(5)
  1254. >>> b.state(3)
  1255. FockStateBosonKet((3,))
  1256. """
  1257. return self.basis[i]
  1258. def __getitem__(self, i):
  1259. return self.state(i)
  1260. def __len__(self):
  1261. return len(self.basis)
  1262. def __repr__(self):
  1263. return repr(self.basis)
  1264. class FixedBosonicBasis(BosonicBasis):
  1265. """
  1266. Fixed particle number basis set.
  1267. Examples
  1268. ========
  1269. >>> from sympy.physics.secondquant import FixedBosonicBasis
  1270. >>> b = FixedBosonicBasis(2, 2)
  1271. >>> state = b.state(1)
  1272. >>> b
  1273. [FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]
  1274. >>> state
  1275. FockStateBosonKet((1, 1))
  1276. >>> b.index(state)
  1277. 1
  1278. """
  1279. def __init__(self, n_particles, n_levels):
  1280. self.n_particles = n_particles
  1281. self.n_levels = n_levels
  1282. self._build_particle_locations()
  1283. self._build_states()
  1284. def _build_particle_locations(self):
  1285. tup = ["i%i" % i for i in range(self.n_particles)]
  1286. first_loop = "for i0 in range(%i)" % self.n_levels
  1287. other_loops = ''
  1288. for cur, prev in zip(tup[1:], tup):
  1289. temp = "for %s in range(%s + 1) " % (cur, prev)
  1290. other_loops = other_loops + temp
  1291. tup_string = "(%s)" % ", ".join(tup)
  1292. list_comp = "[%s %s %s]" % (tup_string, first_loop, other_loops)
  1293. result = eval(list_comp)
  1294. if self.n_particles == 1:
  1295. result = [(item,) for item in result]
  1296. self.particle_locations = result
  1297. def _build_states(self):
  1298. self.basis = []
  1299. for tuple_of_indices in self.particle_locations:
  1300. occ_numbers = self.n_levels*[0]
  1301. for level in tuple_of_indices:
  1302. occ_numbers[level] += 1
  1303. self.basis.append(FockStateBosonKet(occ_numbers))
  1304. self.n_basis = len(self.basis)
  1305. def index(self, state):
  1306. """Returns the index of state in basis.
  1307. Examples
  1308. ========
  1309. >>> from sympy.physics.secondquant import FixedBosonicBasis
  1310. >>> b = FixedBosonicBasis(2, 3)
  1311. >>> b.index(b.state(3))
  1312. 3
  1313. """
  1314. return self.basis.index(state)
  1315. def state(self, i):
  1316. """Returns the state that lies at index i of the basis
  1317. Examples
  1318. ========
  1319. >>> from sympy.physics.secondquant import FixedBosonicBasis
  1320. >>> b = FixedBosonicBasis(2, 3)
  1321. >>> b.state(3)
  1322. FockStateBosonKet((1, 0, 1))
  1323. """
  1324. return self.basis[i]
  1325. def __getitem__(self, i):
  1326. return self.state(i)
  1327. def __len__(self):
  1328. return len(self.basis)
  1329. def __repr__(self):
  1330. return repr(self.basis)
  1331. class Commutator(Function):
  1332. """
  1333. The Commutator: [A, B] = A*B - B*A
  1334. The arguments are ordered according to .__cmp__()
  1335. Examples
  1336. ========
  1337. >>> from sympy import symbols
  1338. >>> from sympy.physics.secondquant import Commutator
  1339. >>> A, B = symbols('A,B', commutative=False)
  1340. >>> Commutator(B, A)
  1341. -Commutator(A, B)
  1342. Evaluate the commutator with .doit()
  1343. >>> comm = Commutator(A,B); comm
  1344. Commutator(A, B)
  1345. >>> comm.doit()
  1346. A*B - B*A
  1347. For two second quantization operators the commutator is evaluated
  1348. immediately:
  1349. >>> from sympy.physics.secondquant import Fd, F
  1350. >>> a = symbols('a', above_fermi=True)
  1351. >>> i = symbols('i', below_fermi=True)
  1352. >>> p,q = symbols('p,q')
  1353. >>> Commutator(Fd(a),Fd(i))
  1354. 2*NO(CreateFermion(a)*CreateFermion(i))
  1355. But for more complicated expressions, the evaluation is triggered by
  1356. a call to .doit()
  1357. >>> comm = Commutator(Fd(p)*Fd(q),F(i)); comm
  1358. Commutator(CreateFermion(p)*CreateFermion(q), AnnihilateFermion(i))
  1359. >>> comm.doit(wicks=True)
  1360. -KroneckerDelta(i, p)*CreateFermion(q) +
  1361. KroneckerDelta(i, q)*CreateFermion(p)
  1362. """
  1363. is_commutative = False
  1364. @classmethod
  1365. def eval(cls, a, b):
  1366. """
  1367. The Commutator [A,B] is on canonical form if A < B.
  1368. Examples
  1369. ========
  1370. >>> from sympy.physics.secondquant import Commutator, F, Fd
  1371. >>> from sympy.abc import x
  1372. >>> c1 = Commutator(F(x), Fd(x))
  1373. >>> c2 = Commutator(Fd(x), F(x))
  1374. >>> Commutator.eval(c1, c2)
  1375. 0
  1376. """
  1377. if not (a and b):
  1378. return S.Zero
  1379. if a == b:
  1380. return S.Zero
  1381. if a.is_commutative or b.is_commutative:
  1382. return S.Zero
  1383. #
  1384. # [A+B,C] -> [A,C] + [B,C]
  1385. #
  1386. a = a.expand()
  1387. if isinstance(a, Add):
  1388. return Add(*[cls(term, b) for term in a.args])
  1389. b = b.expand()
  1390. if isinstance(b, Add):
  1391. return Add(*[cls(a, term) for term in b.args])
  1392. #
  1393. # [xA,yB] -> xy*[A,B]
  1394. #
  1395. ca, nca = a.args_cnc()
  1396. cb, ncb = b.args_cnc()
  1397. c_part = list(ca) + list(cb)
  1398. if c_part:
  1399. return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb)))
  1400. #
  1401. # single second quantization operators
  1402. #
  1403. if isinstance(a, BosonicOperator) and isinstance(b, BosonicOperator):
  1404. if isinstance(b, CreateBoson) and isinstance(a, AnnihilateBoson):
  1405. return KroneckerDelta(a.state, b.state)
  1406. if isinstance(a, CreateBoson) and isinstance(b, AnnihilateBoson):
  1407. return S.NegativeOne*KroneckerDelta(a.state, b.state)
  1408. else:
  1409. return S.Zero
  1410. if isinstance(a, FermionicOperator) and isinstance(b, FermionicOperator):
  1411. return wicks(a*b) - wicks(b*a)
  1412. #
  1413. # Canonical ordering of arguments
  1414. #
  1415. if a.sort_key() > b.sort_key():
  1416. return S.NegativeOne*cls(b, a)
  1417. def doit(self, **hints):
  1418. """
  1419. Enables the computation of complex expressions.
  1420. Examples
  1421. ========
  1422. >>> from sympy.physics.secondquant import Commutator, F, Fd
  1423. >>> from sympy import symbols
  1424. >>> i, j = symbols('i,j', below_fermi=True)
  1425. >>> a, b = symbols('a,b', above_fermi=True)
  1426. >>> c = Commutator(Fd(a)*F(i),Fd(b)*F(j))
  1427. >>> c.doit(wicks=True)
  1428. 0
  1429. """
  1430. a = self.args[0]
  1431. b = self.args[1]
  1432. if hints.get("wicks"):
  1433. a = a.doit(**hints)
  1434. b = b.doit(**hints)
  1435. try:
  1436. return wicks(a*b) - wicks(b*a)
  1437. except ContractionAppliesOnlyToFermions:
  1438. pass
  1439. except WicksTheoremDoesNotApply:
  1440. pass
  1441. return (a*b - b*a).doit(**hints)
  1442. def __repr__(self):
  1443. return "Commutator(%s,%s)" % (self.args[0], self.args[1])
  1444. def __str__(self):
  1445. return "[%s,%s]" % (self.args[0], self.args[1])
  1446. def _latex(self, printer):
  1447. return "\\left[%s,%s\\right]" % tuple([
  1448. printer._print(arg) for arg in self.args])
  1449. class NO(Expr):
  1450. """
  1451. This Object is used to represent normal ordering brackets.
  1452. i.e. {abcd} sometimes written :abcd:
  1453. Explanation
  1454. ===========
  1455. Applying the function NO(arg) to an argument means that all operators in
  1456. the argument will be assumed to anticommute, and have vanishing
  1457. contractions. This allows an immediate reordering to canonical form
  1458. upon object creation.
  1459. Examples
  1460. ========
  1461. >>> from sympy import symbols
  1462. >>> from sympy.physics.secondquant import NO, F, Fd
  1463. >>> p,q = symbols('p,q')
  1464. >>> NO(Fd(p)*F(q))
  1465. NO(CreateFermion(p)*AnnihilateFermion(q))
  1466. >>> NO(F(q)*Fd(p))
  1467. -NO(CreateFermion(p)*AnnihilateFermion(q))
  1468. Note
  1469. ====
  1470. If you want to generate a normal ordered equivalent of an expression, you
  1471. should use the function wicks(). This class only indicates that all
  1472. operators inside the brackets anticommute, and have vanishing contractions.
  1473. Nothing more, nothing less.
  1474. """
  1475. is_commutative = False
  1476. def __new__(cls, arg):
  1477. """
  1478. Use anticommutation to get canonical form of operators.
  1479. Explanation
  1480. ===========
  1481. Employ associativity of normal ordered product: {ab{cd}} = {abcd}
  1482. but note that {ab}{cd} /= {abcd}.
  1483. We also employ distributivity: {ab + cd} = {ab} + {cd}.
  1484. Canonical form also implies expand() {ab(c+d)} = {abc} + {abd}.
  1485. """
  1486. # {ab + cd} = {ab} + {cd}
  1487. arg = sympify(arg)
  1488. arg = arg.expand()
  1489. if arg.is_Add:
  1490. return Add(*[ cls(term) for term in arg.args])
  1491. if arg.is_Mul:
  1492. # take coefficient outside of normal ordering brackets
  1493. c_part, seq = arg.args_cnc()
  1494. if c_part:
  1495. coeff = Mul(*c_part)
  1496. if not seq:
  1497. return coeff
  1498. else:
  1499. coeff = S.One
  1500. # {ab{cd}} = {abcd}
  1501. newseq = []
  1502. foundit = False
  1503. for fac in seq:
  1504. if isinstance(fac, NO):
  1505. newseq.extend(fac.args)
  1506. foundit = True
  1507. else:
  1508. newseq.append(fac)
  1509. if foundit:
  1510. return coeff*cls(Mul(*newseq))
  1511. # We assume that the user don't mix B and F operators
  1512. if isinstance(seq[0], BosonicOperator):
  1513. raise NotImplementedError
  1514. try:
  1515. newseq, sign = _sort_anticommuting_fermions(seq)
  1516. except ViolationOfPauliPrinciple:
  1517. return S.Zero
  1518. if sign % 2:
  1519. return (S.NegativeOne*coeff)*cls(Mul(*newseq))
  1520. elif sign:
  1521. return coeff*cls(Mul(*newseq))
  1522. else:
  1523. pass # since sign==0, no permutations was necessary
  1524. # if we couldn't do anything with Mul object, we just
  1525. # mark it as normal ordered
  1526. if coeff != S.One:
  1527. return coeff*cls(Mul(*newseq))
  1528. return Expr.__new__(cls, Mul(*newseq))
  1529. if isinstance(arg, NO):
  1530. return arg
  1531. # if object was not Mul or Add, normal ordering does not apply
  1532. return arg
  1533. @property
  1534. def has_q_creators(self):
  1535. """
  1536. Return 0 if the leftmost argument of the first argument is a not a
  1537. q_creator, else 1 if it is above fermi or -1 if it is below fermi.
  1538. Examples
  1539. ========
  1540. >>> from sympy import symbols
  1541. >>> from sympy.physics.secondquant import NO, F, Fd
  1542. >>> a = symbols('a', above_fermi=True)
  1543. >>> i = symbols('i', below_fermi=True)
  1544. >>> NO(Fd(a)*Fd(i)).has_q_creators
  1545. 1
  1546. >>> NO(F(i)*F(a)).has_q_creators
  1547. -1
  1548. >>> NO(Fd(i)*F(a)).has_q_creators #doctest: +SKIP
  1549. 0
  1550. """
  1551. return self.args[0].args[0].is_q_creator
  1552. @property
  1553. def has_q_annihilators(self):
  1554. """
  1555. Return 0 if the rightmost argument of the first argument is a not a
  1556. q_annihilator, else 1 if it is above fermi or -1 if it is below fermi.
  1557. Examples
  1558. ========
  1559. >>> from sympy import symbols
  1560. >>> from sympy.physics.secondquant import NO, F, Fd
  1561. >>> a = symbols('a', above_fermi=True)
  1562. >>> i = symbols('i', below_fermi=True)
  1563. >>> NO(Fd(a)*Fd(i)).has_q_annihilators
  1564. -1
  1565. >>> NO(F(i)*F(a)).has_q_annihilators
  1566. 1
  1567. >>> NO(Fd(a)*F(i)).has_q_annihilators
  1568. 0
  1569. """
  1570. return self.args[0].args[-1].is_q_annihilator
  1571. def doit(self, **kw_args):
  1572. """
  1573. Either removes the brackets or enables complex computations
  1574. in its arguments.
  1575. Examples
  1576. ========
  1577. >>> from sympy.physics.secondquant import NO, Fd, F
  1578. >>> from textwrap import fill
  1579. >>> from sympy import symbols, Dummy
  1580. >>> p,q = symbols('p,q', cls=Dummy)
  1581. >>> print(fill(str(NO(Fd(p)*F(q)).doit())))
  1582. KroneckerDelta(_a, _p)*KroneckerDelta(_a,
  1583. _q)*CreateFermion(_a)*AnnihilateFermion(_a) + KroneckerDelta(_a,
  1584. _p)*KroneckerDelta(_i, _q)*CreateFermion(_a)*AnnihilateFermion(_i) -
  1585. KroneckerDelta(_a, _q)*KroneckerDelta(_i,
  1586. _p)*AnnihilateFermion(_a)*CreateFermion(_i) - KroneckerDelta(_i,
  1587. _p)*KroneckerDelta(_i, _q)*AnnihilateFermion(_i)*CreateFermion(_i)
  1588. """
  1589. if kw_args.get("remove_brackets", True):
  1590. return self._remove_brackets()
  1591. else:
  1592. return self.__new__(type(self), self.args[0].doit(**kw_args))
  1593. def _remove_brackets(self):
  1594. """
  1595. Returns the sorted string without normal order brackets.
  1596. The returned string have the property that no nonzero
  1597. contractions exist.
  1598. """
  1599. # check if any creator is also an annihilator
  1600. subslist = []
  1601. for i in self.iter_q_creators():
  1602. if self[i].is_q_annihilator:
  1603. assume = self[i].state.assumptions0
  1604. # only operators with a dummy index can be split in two terms
  1605. if isinstance(self[i].state, Dummy):
  1606. # create indices with fermi restriction
  1607. assume.pop("above_fermi", None)
  1608. assume["below_fermi"] = True
  1609. below = Dummy('i', **assume)
  1610. assume.pop("below_fermi", None)
  1611. assume["above_fermi"] = True
  1612. above = Dummy('a', **assume)
  1613. cls = type(self[i])
  1614. split = (
  1615. self[i].__new__(cls, below)
  1616. * KroneckerDelta(below, self[i].state)
  1617. + self[i].__new__(cls, above)
  1618. * KroneckerDelta(above, self[i].state)
  1619. )
  1620. subslist.append((self[i], split))
  1621. else:
  1622. raise SubstitutionOfAmbigousOperatorFailed(self[i])
  1623. if subslist:
  1624. result = NO(self.subs(subslist))
  1625. if isinstance(result, Add):
  1626. return Add(*[term.doit() for term in result.args])
  1627. else:
  1628. return self.args[0]
  1629. def _expand_operators(self):
  1630. """
  1631. Returns a sum of NO objects that contain no ambiguous q-operators.
  1632. Explanation
  1633. ===========
  1634. If an index q has range both above and below fermi, the operator F(q)
  1635. is ambiguous in the sense that it can be both a q-creator and a q-annihilator.
  1636. If q is dummy, it is assumed to be a summation variable and this method
  1637. rewrites it into a sum of NO terms with unambiguous operators:
  1638. {Fd(p)*F(q)} = {Fd(a)*F(b)} + {Fd(a)*F(i)} + {Fd(j)*F(b)} -{F(i)*Fd(j)}
  1639. where a,b are above and i,j are below fermi level.
  1640. """
  1641. return NO(self._remove_brackets)
  1642. def __getitem__(self, i):
  1643. if isinstance(i, slice):
  1644. indices = i.indices(len(self))
  1645. return [self.args[0].args[i] for i in range(*indices)]
  1646. else:
  1647. return self.args[0].args[i]
  1648. def __len__(self):
  1649. return len(self.args[0].args)
  1650. def iter_q_annihilators(self):
  1651. """
  1652. Iterates over the annihilation operators.
  1653. Examples
  1654. ========
  1655. >>> from sympy import symbols
  1656. >>> i, j = symbols('i j', below_fermi=True)
  1657. >>> a, b = symbols('a b', above_fermi=True)
  1658. >>> from sympy.physics.secondquant import NO, F, Fd
  1659. >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j))
  1660. >>> no.iter_q_creators()
  1661. <generator object... at 0x...>
  1662. >>> list(no.iter_q_creators())
  1663. [0, 1]
  1664. >>> list(no.iter_q_annihilators())
  1665. [3, 2]
  1666. """
  1667. ops = self.args[0].args
  1668. iter = range(len(ops) - 1, -1, -1)
  1669. for i in iter:
  1670. if ops[i].is_q_annihilator:
  1671. yield i
  1672. else:
  1673. break
  1674. def iter_q_creators(self):
  1675. """
  1676. Iterates over the creation operators.
  1677. Examples
  1678. ========
  1679. >>> from sympy import symbols
  1680. >>> i, j = symbols('i j', below_fermi=True)
  1681. >>> a, b = symbols('a b', above_fermi=True)
  1682. >>> from sympy.physics.secondquant import NO, F, Fd
  1683. >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j))
  1684. >>> no.iter_q_creators()
  1685. <generator object... at 0x...>
  1686. >>> list(no.iter_q_creators())
  1687. [0, 1]
  1688. >>> list(no.iter_q_annihilators())
  1689. [3, 2]
  1690. """
  1691. ops = self.args[0].args
  1692. iter = range(0, len(ops))
  1693. for i in iter:
  1694. if ops[i].is_q_creator:
  1695. yield i
  1696. else:
  1697. break
  1698. def get_subNO(self, i):
  1699. """
  1700. Returns a NO() without FermionicOperator at index i.
  1701. Examples
  1702. ========
  1703. >>> from sympy import symbols
  1704. >>> from sympy.physics.secondquant import F, NO
  1705. >>> p, q, r = symbols('p,q,r')
  1706. >>> NO(F(p)*F(q)*F(r)).get_subNO(1)
  1707. NO(AnnihilateFermion(p)*AnnihilateFermion(r))
  1708. """
  1709. arg0 = self.args[0] # it's a Mul by definition of how it's created
  1710. mul = arg0._new_rawargs(*(arg0.args[:i] + arg0.args[i + 1:]))
  1711. return NO(mul)
  1712. def _latex(self, printer):
  1713. return "\\left\\{%s\\right\\}" % printer._print(self.args[0])
  1714. def __repr__(self):
  1715. return "NO(%s)" % self.args[0]
  1716. def __str__(self):
  1717. return ":%s:" % self.args[0]
  1718. def contraction(a, b):
  1719. """
  1720. Calculates contraction of Fermionic operators a and b.
  1721. Examples
  1722. ========
  1723. >>> from sympy import symbols
  1724. >>> from sympy.physics.secondquant import F, Fd, contraction
  1725. >>> p, q = symbols('p,q')
  1726. >>> a, b = symbols('a,b', above_fermi=True)
  1727. >>> i, j = symbols('i,j', below_fermi=True)
  1728. A contraction is non-zero only if a quasi-creator is to the right of a
  1729. quasi-annihilator:
  1730. >>> contraction(F(a),Fd(b))
  1731. KroneckerDelta(a, b)
  1732. >>> contraction(Fd(i),F(j))
  1733. KroneckerDelta(i, j)
  1734. For general indices a non-zero result restricts the indices to below/above
  1735. the fermi surface:
  1736. >>> contraction(Fd(p),F(q))
  1737. KroneckerDelta(_i, q)*KroneckerDelta(p, q)
  1738. >>> contraction(F(p),Fd(q))
  1739. KroneckerDelta(_a, q)*KroneckerDelta(p, q)
  1740. Two creators or two annihilators always vanishes:
  1741. >>> contraction(F(p),F(q))
  1742. 0
  1743. >>> contraction(Fd(p),Fd(q))
  1744. 0
  1745. """
  1746. if isinstance(b, FermionicOperator) and isinstance(a, FermionicOperator):
  1747. if isinstance(a, AnnihilateFermion) and isinstance(b, CreateFermion):
  1748. if b.state.assumptions0.get("below_fermi"):
  1749. return S.Zero
  1750. if a.state.assumptions0.get("below_fermi"):
  1751. return S.Zero
  1752. if b.state.assumptions0.get("above_fermi"):
  1753. return KroneckerDelta(a.state, b.state)
  1754. if a.state.assumptions0.get("above_fermi"):
  1755. return KroneckerDelta(a.state, b.state)
  1756. return (KroneckerDelta(a.state, b.state)*
  1757. KroneckerDelta(b.state, Dummy('a', above_fermi=True)))
  1758. if isinstance(b, AnnihilateFermion) and isinstance(a, CreateFermion):
  1759. if b.state.assumptions0.get("above_fermi"):
  1760. return S.Zero
  1761. if a.state.assumptions0.get("above_fermi"):
  1762. return S.Zero
  1763. if b.state.assumptions0.get("below_fermi"):
  1764. return KroneckerDelta(a.state, b.state)
  1765. if a.state.assumptions0.get("below_fermi"):
  1766. return KroneckerDelta(a.state, b.state)
  1767. return (KroneckerDelta(a.state, b.state)*
  1768. KroneckerDelta(b.state, Dummy('i', below_fermi=True)))
  1769. # vanish if 2xAnnihilator or 2xCreator
  1770. return S.Zero
  1771. else:
  1772. #not fermion operators
  1773. t = ( isinstance(i, FermionicOperator) for i in (a, b) )
  1774. raise ContractionAppliesOnlyToFermions(*t)
  1775. def _sqkey(sq_operator):
  1776. """Generates key for canonical sorting of SQ operators."""
  1777. return sq_operator._sortkey()
  1778. def _sort_anticommuting_fermions(string1, key=_sqkey):
  1779. """Sort fermionic operators to canonical order, assuming all pairs anticommute.
  1780. Explanation
  1781. ===========
  1782. Uses a bidirectional bubble sort. Items in string1 are not referenced
  1783. so in principle they may be any comparable objects. The sorting depends on the
  1784. operators '>' and '=='.
  1785. If the Pauli principle is violated, an exception is raised.
  1786. Returns
  1787. =======
  1788. tuple (sorted_str, sign)
  1789. sorted_str: list containing the sorted operators
  1790. sign: int telling how many times the sign should be changed
  1791. (if sign==0 the string was already sorted)
  1792. """
  1793. verified = False
  1794. sign = 0
  1795. rng = list(range(len(string1) - 1))
  1796. rev = list(range(len(string1) - 3, -1, -1))
  1797. keys = list(map(key, string1))
  1798. key_val = dict(list(zip(keys, string1)))
  1799. while not verified:
  1800. verified = True
  1801. for i in rng:
  1802. left = keys[i]
  1803. right = keys[i + 1]
  1804. if left == right:
  1805. raise ViolationOfPauliPrinciple([left, right])
  1806. if left > right:
  1807. verified = False
  1808. keys[i:i + 2] = [right, left]
  1809. sign = sign + 1
  1810. if verified:
  1811. break
  1812. for i in rev:
  1813. left = keys[i]
  1814. right = keys[i + 1]
  1815. if left == right:
  1816. raise ViolationOfPauliPrinciple([left, right])
  1817. if left > right:
  1818. verified = False
  1819. keys[i:i + 2] = [right, left]
  1820. sign = sign + 1
  1821. string1 = [ key_val[k] for k in keys ]
  1822. return (string1, sign)
  1823. def evaluate_deltas(e):
  1824. """
  1825. We evaluate KroneckerDelta symbols in the expression assuming Einstein summation.
  1826. Explanation
  1827. ===========
  1828. If one index is repeated it is summed over and in effect substituted with
  1829. the other one. If both indices are repeated we substitute according to what
  1830. is the preferred index. this is determined by
  1831. KroneckerDelta.preferred_index and KroneckerDelta.killable_index.
  1832. In case there are no possible substitutions or if a substitution would
  1833. imply a loss of information, nothing is done.
  1834. In case an index appears in more than one KroneckerDelta, the resulting
  1835. substitution depends on the order of the factors. Since the ordering is platform
  1836. dependent, the literal expression resulting from this function may be hard to
  1837. predict.
  1838. Examples
  1839. ========
  1840. We assume the following:
  1841. >>> from sympy import symbols, Function, Dummy, KroneckerDelta
  1842. >>> from sympy.physics.secondquant import evaluate_deltas
  1843. >>> i,j = symbols('i j', below_fermi=True, cls=Dummy)
  1844. >>> a,b = symbols('a b', above_fermi=True, cls=Dummy)
  1845. >>> p,q = symbols('p q', cls=Dummy)
  1846. >>> f = Function('f')
  1847. >>> t = Function('t')
  1848. The order of preference for these indices according to KroneckerDelta is
  1849. (a, b, i, j, p, q).
  1850. Trivial cases:
  1851. >>> evaluate_deltas(KroneckerDelta(i,j)*f(i)) # d_ij f(i) -> f(j)
  1852. f(_j)
  1853. >>> evaluate_deltas(KroneckerDelta(i,j)*f(j)) # d_ij f(j) -> f(i)
  1854. f(_i)
  1855. >>> evaluate_deltas(KroneckerDelta(i,p)*f(p)) # d_ip f(p) -> f(i)
  1856. f(_i)
  1857. >>> evaluate_deltas(KroneckerDelta(q,p)*f(p)) # d_qp f(p) -> f(q)
  1858. f(_q)
  1859. >>> evaluate_deltas(KroneckerDelta(q,p)*f(q)) # d_qp f(q) -> f(p)
  1860. f(_p)
  1861. More interesting cases:
  1862. >>> evaluate_deltas(KroneckerDelta(i,p)*t(a,i)*f(p,q))
  1863. f(_i, _q)*t(_a, _i)
  1864. >>> evaluate_deltas(KroneckerDelta(a,p)*t(a,i)*f(p,q))
  1865. f(_a, _q)*t(_a, _i)
  1866. >>> evaluate_deltas(KroneckerDelta(p,q)*f(p,q))
  1867. f(_p, _p)
  1868. Finally, here are some cases where nothing is done, because that would
  1869. imply a loss of information:
  1870. >>> evaluate_deltas(KroneckerDelta(i,p)*f(q))
  1871. f(_q)*KroneckerDelta(_i, _p)
  1872. >>> evaluate_deltas(KroneckerDelta(i,p)*f(i))
  1873. f(_i)*KroneckerDelta(_i, _p)
  1874. """
  1875. # We treat Deltas only in mul objects
  1876. # for general function objects we don't evaluate KroneckerDeltas in arguments,
  1877. # but here we hard code exceptions to this rule
  1878. accepted_functions = (
  1879. Add,
  1880. )
  1881. if isinstance(e, accepted_functions):
  1882. return e.func(*[evaluate_deltas(arg) for arg in e.args])
  1883. elif isinstance(e, Mul):
  1884. # find all occurrences of delta function and count each index present in
  1885. # expression.
  1886. deltas = []
  1887. indices = {}
  1888. for i in e.args:
  1889. for s in i.free_symbols:
  1890. if s in indices:
  1891. indices[s] += 1
  1892. else:
  1893. indices[s] = 0 # geek counting simplifies logic below
  1894. if isinstance(i, KroneckerDelta):
  1895. deltas.append(i)
  1896. for d in deltas:
  1897. # If we do something, and there are more deltas, we should recurse
  1898. # to treat the resulting expression properly
  1899. if d.killable_index.is_Symbol and indices[d.killable_index]:
  1900. e = e.subs(d.killable_index, d.preferred_index)
  1901. if len(deltas) > 1:
  1902. return evaluate_deltas(e)
  1903. elif (d.preferred_index.is_Symbol and indices[d.preferred_index]
  1904. and d.indices_contain_equal_information):
  1905. e = e.subs(d.preferred_index, d.killable_index)
  1906. if len(deltas) > 1:
  1907. return evaluate_deltas(e)
  1908. else:
  1909. pass
  1910. return e
  1911. # nothing to do, maybe we hit a Symbol or a number
  1912. else:
  1913. return e
  1914. def substitute_dummies(expr, new_indices=False, pretty_indices={}):
  1915. """
  1916. Collect terms by substitution of dummy variables.
  1917. Explanation
  1918. ===========
  1919. This routine allows simplification of Add expressions containing terms
  1920. which differ only due to dummy variables.
  1921. The idea is to substitute all dummy variables consistently depending on
  1922. the structure of the term. For each term, we obtain a sequence of all
  1923. dummy variables, where the order is determined by the index range, what
  1924. factors the index belongs to and its position in each factor. See
  1925. _get_ordered_dummies() for more information about the sorting of dummies.
  1926. The index sequence is then substituted consistently in each term.
  1927. Examples
  1928. ========
  1929. >>> from sympy import symbols, Function, Dummy
  1930. >>> from sympy.physics.secondquant import substitute_dummies
  1931. >>> a,b,c,d = symbols('a b c d', above_fermi=True, cls=Dummy)
  1932. >>> i,j = symbols('i j', below_fermi=True, cls=Dummy)
  1933. >>> f = Function('f')
  1934. >>> expr = f(a,b) + f(c,d); expr
  1935. f(_a, _b) + f(_c, _d)
  1936. Since a, b, c and d are equivalent summation indices, the expression can be
  1937. simplified to a single term (for which the dummy indices are still summed over)
  1938. >>> substitute_dummies(expr)
  1939. 2*f(_a, _b)
  1940. Controlling output:
  1941. By default the dummy symbols that are already present in the expression
  1942. will be reused in a different permutation. However, if new_indices=True,
  1943. new dummies will be generated and inserted. The keyword 'pretty_indices'
  1944. can be used to control this generation of new symbols.
  1945. By default the new dummies will be generated on the form i_1, i_2, a_1,
  1946. etc. If you supply a dictionary with key:value pairs in the form:
  1947. { index_group: string_of_letters }
  1948. The letters will be used as labels for the new dummy symbols. The
  1949. index_groups must be one of 'above', 'below' or 'general'.
  1950. >>> expr = f(a,b,i,j)
  1951. >>> my_dummies = { 'above':'st', 'below':'uv' }
  1952. >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies)
  1953. f(_s, _t, _u, _v)
  1954. If we run out of letters, or if there is no keyword for some index_group
  1955. the default dummy generator will be used as a fallback:
  1956. >>> p,q = symbols('p q', cls=Dummy) # general indices
  1957. >>> expr = f(p,q)
  1958. >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies)
  1959. f(_p_0, _p_1)
  1960. """
  1961. # setup the replacing dummies
  1962. if new_indices:
  1963. letters_above = pretty_indices.get('above', "")
  1964. letters_below = pretty_indices.get('below', "")
  1965. letters_general = pretty_indices.get('general', "")
  1966. len_above = len(letters_above)
  1967. len_below = len(letters_below)
  1968. len_general = len(letters_general)
  1969. def _i(number):
  1970. try:
  1971. return letters_below[number]
  1972. except IndexError:
  1973. return 'i_' + str(number - len_below)
  1974. def _a(number):
  1975. try:
  1976. return letters_above[number]
  1977. except IndexError:
  1978. return 'a_' + str(number - len_above)
  1979. def _p(number):
  1980. try:
  1981. return letters_general[number]
  1982. except IndexError:
  1983. return 'p_' + str(number - len_general)
  1984. aboves = []
  1985. belows = []
  1986. generals = []
  1987. dummies = expr.atoms(Dummy)
  1988. if not new_indices:
  1989. dummies = sorted(dummies, key=default_sort_key)
  1990. # generate lists with the dummies we will insert
  1991. a = i = p = 0
  1992. for d in dummies:
  1993. assum = d.assumptions0
  1994. if assum.get("above_fermi"):
  1995. if new_indices:
  1996. sym = _a(a)
  1997. a += 1
  1998. l1 = aboves
  1999. elif assum.get("below_fermi"):
  2000. if new_indices:
  2001. sym = _i(i)
  2002. i += 1
  2003. l1 = belows
  2004. else:
  2005. if new_indices:
  2006. sym = _p(p)
  2007. p += 1
  2008. l1 = generals
  2009. if new_indices:
  2010. l1.append(Dummy(sym, **assum))
  2011. else:
  2012. l1.append(d)
  2013. expr = expr.expand()
  2014. terms = Add.make_args(expr)
  2015. new_terms = []
  2016. for term in terms:
  2017. i = iter(belows)
  2018. a = iter(aboves)
  2019. p = iter(generals)
  2020. ordered = _get_ordered_dummies(term)
  2021. subsdict = {}
  2022. for d in ordered:
  2023. if d.assumptions0.get('below_fermi'):
  2024. subsdict[d] = next(i)
  2025. elif d.assumptions0.get('above_fermi'):
  2026. subsdict[d] = next(a)
  2027. else:
  2028. subsdict[d] = next(p)
  2029. subslist = []
  2030. final_subs = []
  2031. for k, v in subsdict.items():
  2032. if k == v:
  2033. continue
  2034. if v in subsdict:
  2035. # We check if the sequence of substitutions end quickly. In
  2036. # that case, we can avoid temporary symbols if we ensure the
  2037. # correct substitution order.
  2038. if subsdict[v] in subsdict:
  2039. # (x, y) -> (y, x), we need a temporary variable
  2040. x = Dummy('x')
  2041. subslist.append((k, x))
  2042. final_subs.append((x, v))
  2043. else:
  2044. # (x, y) -> (y, a), x->y must be done last
  2045. # but before temporary variables are resolved
  2046. final_subs.insert(0, (k, v))
  2047. else:
  2048. subslist.append((k, v))
  2049. subslist.extend(final_subs)
  2050. new_terms.append(term.subs(subslist))
  2051. return Add(*new_terms)
  2052. class KeyPrinter(StrPrinter):
  2053. """Printer for which only equal objects are equal in print"""
  2054. def _print_Dummy(self, expr):
  2055. return "(%s_%i)" % (expr.name, expr.dummy_index)
  2056. def __kprint(expr):
  2057. p = KeyPrinter()
  2058. return p.doprint(expr)
  2059. def _get_ordered_dummies(mul, verbose=False):
  2060. """Returns all dummies in the mul sorted in canonical order.
  2061. Explanation
  2062. ===========
  2063. The purpose of the canonical ordering is that dummies can be substituted
  2064. consistently across terms with the result that equivalent terms can be
  2065. simplified.
  2066. It is not possible to determine if two terms are equivalent based solely on
  2067. the dummy order. However, a consistent substitution guided by the ordered
  2068. dummies should lead to trivially (non-)equivalent terms, thereby revealing
  2069. the equivalence. This also means that if two terms have identical sequences of
  2070. dummies, the (non-)equivalence should already be apparent.
  2071. Strategy
  2072. --------
  2073. The canoncial order is given by an arbitrary sorting rule. A sort key
  2074. is determined for each dummy as a tuple that depends on all factors where
  2075. the index is present. The dummies are thereby sorted according to the
  2076. contraction structure of the term, instead of sorting based solely on the
  2077. dummy symbol itself.
  2078. After all dummies in the term has been assigned a key, we check for identical
  2079. keys, i.e. unorderable dummies. If any are found, we call a specialized
  2080. method, _determine_ambiguous(), that will determine a unique order based
  2081. on recursive calls to _get_ordered_dummies().
  2082. Key description
  2083. ---------------
  2084. A high level description of the sort key:
  2085. 1. Range of the dummy index
  2086. 2. Relation to external (non-dummy) indices
  2087. 3. Position of the index in the first factor
  2088. 4. Position of the index in the second factor
  2089. The sort key is a tuple with the following components:
  2090. 1. A single character indicating the range of the dummy (above, below
  2091. or general.)
  2092. 2. A list of strings with fully masked string representations of all
  2093. factors where the dummy is present. By masked, we mean that dummies
  2094. are represented by a symbol to indicate either below fermi, above or
  2095. general. No other information is displayed about the dummies at
  2096. this point. The list is sorted stringwise.
  2097. 3. An integer number indicating the position of the index, in the first
  2098. factor as sorted in 2.
  2099. 4. An integer number indicating the position of the index, in the second
  2100. factor as sorted in 2.
  2101. If a factor is either of type AntiSymmetricTensor or SqOperator, the index
  2102. position in items 3 and 4 is indicated as 'upper' or 'lower' only.
  2103. (Creation operators are considered upper and annihilation operators lower.)
  2104. If the masked factors are identical, the two factors cannot be ordered
  2105. unambiguously in item 2. In this case, items 3, 4 are left out. If several
  2106. indices are contracted between the unorderable factors, it will be handled by
  2107. _determine_ambiguous()
  2108. """
  2109. # setup dicts to avoid repeated calculations in key()
  2110. args = Mul.make_args(mul)
  2111. fac_dum = { fac: fac.atoms(Dummy) for fac in args }
  2112. fac_repr = { fac: __kprint(fac) for fac in args }
  2113. all_dums = set().union(*fac_dum.values())
  2114. mask = {}
  2115. for d in all_dums:
  2116. if d.assumptions0.get('below_fermi'):
  2117. mask[d] = '0'
  2118. elif d.assumptions0.get('above_fermi'):
  2119. mask[d] = '1'
  2120. else:
  2121. mask[d] = '2'
  2122. dum_repr = {d: __kprint(d) for d in all_dums}
  2123. def _key(d):
  2124. dumstruct = [ fac for fac in fac_dum if d in fac_dum[fac] ]
  2125. other_dums = set().union(*[fac_dum[fac] for fac in dumstruct])
  2126. fac = dumstruct[-1]
  2127. if other_dums is fac_dum[fac]:
  2128. other_dums = fac_dum[fac].copy()
  2129. other_dums.remove(d)
  2130. masked_facs = [ fac_repr[fac] for fac in dumstruct ]
  2131. for d2 in other_dums:
  2132. masked_facs = [ fac.replace(dum_repr[d2], mask[d2])
  2133. for fac in masked_facs ]
  2134. all_masked = [ fac.replace(dum_repr[d], mask[d])
  2135. for fac in masked_facs ]
  2136. masked_facs = dict(list(zip(dumstruct, masked_facs)))
  2137. # dummies for which the ordering cannot be determined
  2138. if has_dups(all_masked):
  2139. all_masked.sort()
  2140. return mask[d], tuple(all_masked) # positions are ambiguous
  2141. # sort factors according to fully masked strings
  2142. keydict = dict(list(zip(dumstruct, all_masked)))
  2143. dumstruct.sort(key=lambda x: keydict[x])
  2144. all_masked.sort()
  2145. pos_val = []
  2146. for fac in dumstruct:
  2147. if isinstance(fac, AntiSymmetricTensor):
  2148. if d in fac.upper:
  2149. pos_val.append('u')
  2150. if d in fac.lower:
  2151. pos_val.append('l')
  2152. elif isinstance(fac, Creator):
  2153. pos_val.append('u')
  2154. elif isinstance(fac, Annihilator):
  2155. pos_val.append('l')
  2156. elif isinstance(fac, NO):
  2157. ops = [ op for op in fac if op.has(d) ]
  2158. for op in ops:
  2159. if isinstance(op, Creator):
  2160. pos_val.append('u')
  2161. else:
  2162. pos_val.append('l')
  2163. else:
  2164. # fallback to position in string representation
  2165. facpos = -1
  2166. while 1:
  2167. facpos = masked_facs[fac].find(dum_repr[d], facpos + 1)
  2168. if facpos == -1:
  2169. break
  2170. pos_val.append(facpos)
  2171. return (mask[d], tuple(all_masked), pos_val[0], pos_val[-1])
  2172. dumkey = dict(list(zip(all_dums, list(map(_key, all_dums)))))
  2173. result = sorted(all_dums, key=lambda x: dumkey[x])
  2174. if has_dups(iter(dumkey.values())):
  2175. # We have ambiguities
  2176. unordered = defaultdict(set)
  2177. for d, k in dumkey.items():
  2178. unordered[k].add(d)
  2179. for k in [ k for k in unordered if len(unordered[k]) < 2 ]:
  2180. del unordered[k]
  2181. unordered = [ unordered[k] for k in sorted(unordered) ]
  2182. result = _determine_ambiguous(mul, result, unordered)
  2183. return result
  2184. def _determine_ambiguous(term, ordered, ambiguous_groups):
  2185. # We encountered a term for which the dummy substitution is ambiguous.
  2186. # This happens for terms with 2 or more contractions between factors that
  2187. # cannot be uniquely ordered independent of summation indices. For
  2188. # example:
  2189. #
  2190. # Sum(p, q) v^{p, .}_{q, .}v^{q, .}_{p, .}
  2191. #
  2192. # Assuming that the indices represented by . are dummies with the
  2193. # same range, the factors cannot be ordered, and there is no
  2194. # way to determine a consistent ordering of p and q.
  2195. #
  2196. # The strategy employed here, is to relabel all unambiguous dummies with
  2197. # non-dummy symbols and call _get_ordered_dummies again. This procedure is
  2198. # applied to the entire term so there is a possibility that
  2199. # _determine_ambiguous() is called again from a deeper recursion level.
  2200. # break recursion if there are no ordered dummies
  2201. all_ambiguous = set()
  2202. for dummies in ambiguous_groups:
  2203. all_ambiguous |= dummies
  2204. all_ordered = set(ordered) - all_ambiguous
  2205. if not all_ordered:
  2206. # FIXME: If we arrive here, there are no ordered dummies. A method to
  2207. # handle this needs to be implemented. In order to return something
  2208. # useful nevertheless, we choose arbitrarily the first dummy and
  2209. # determine the rest from this one. This method is dependent on the
  2210. # actual dummy labels which violates an assumption for the
  2211. # canonicalization procedure. A better implementation is needed.
  2212. group = [ d for d in ordered if d in ambiguous_groups[0] ]
  2213. d = group[0]
  2214. all_ordered.add(d)
  2215. ambiguous_groups[0].remove(d)
  2216. stored_counter = _symbol_factory._counter
  2217. subslist = []
  2218. for d in [ d for d in ordered if d in all_ordered ]:
  2219. nondum = _symbol_factory._next()
  2220. subslist.append((d, nondum))
  2221. newterm = term.subs(subslist)
  2222. neworder = _get_ordered_dummies(newterm)
  2223. _symbol_factory._set_counter(stored_counter)
  2224. # update ordered list with new information
  2225. for group in ambiguous_groups:
  2226. ordered_group = [ d for d in neworder if d in group ]
  2227. ordered_group.reverse()
  2228. result = []
  2229. for d in ordered:
  2230. if d in group:
  2231. result.append(ordered_group.pop())
  2232. else:
  2233. result.append(d)
  2234. ordered = result
  2235. return ordered
  2236. class _SymbolFactory:
  2237. def __init__(self, label):
  2238. self._counterVar = 0
  2239. self._label = label
  2240. def _set_counter(self, value):
  2241. """
  2242. Sets counter to value.
  2243. """
  2244. self._counterVar = value
  2245. @property
  2246. def _counter(self):
  2247. """
  2248. What counter is currently at.
  2249. """
  2250. return self._counterVar
  2251. def _next(self):
  2252. """
  2253. Generates the next symbols and increments counter by 1.
  2254. """
  2255. s = Symbol("%s%i" % (self._label, self._counterVar))
  2256. self._counterVar += 1
  2257. return s
  2258. _symbol_factory = _SymbolFactory('_]"]_') # most certainly a unique label
  2259. @cacheit
  2260. def _get_contractions(string1, keep_only_fully_contracted=False):
  2261. """
  2262. Returns Add-object with contracted terms.
  2263. Uses recursion to find all contractions. -- Internal helper function --
  2264. Will find nonzero contractions in string1 between indices given in
  2265. leftrange and rightrange.
  2266. """
  2267. # Should we store current level of contraction?
  2268. if keep_only_fully_contracted and string1:
  2269. result = []
  2270. else:
  2271. result = [NO(Mul(*string1))]
  2272. for i in range(len(string1) - 1):
  2273. for j in range(i + 1, len(string1)):
  2274. c = contraction(string1[i], string1[j])
  2275. if c:
  2276. sign = (j - i + 1) % 2
  2277. if sign:
  2278. coeff = S.NegativeOne*c
  2279. else:
  2280. coeff = c
  2281. #
  2282. # Call next level of recursion
  2283. # ============================
  2284. #
  2285. # We now need to find more contractions among operators
  2286. #
  2287. # oplist = string1[:i]+ string1[i+1:j] + string1[j+1:]
  2288. #
  2289. # To prevent overcounting, we don't allow contractions
  2290. # we have already encountered. i.e. contractions between
  2291. # string1[:i] <---> string1[i+1:j]
  2292. # and string1[:i] <---> string1[j+1:].
  2293. #
  2294. # This leaves the case:
  2295. oplist = string1[i + 1:j] + string1[j + 1:]
  2296. if oplist:
  2297. result.append(coeff*NO(
  2298. Mul(*string1[:i])*_get_contractions( oplist,
  2299. keep_only_fully_contracted=keep_only_fully_contracted)))
  2300. else:
  2301. result.append(coeff*NO( Mul(*string1[:i])))
  2302. if keep_only_fully_contracted:
  2303. break # next iteration over i leaves leftmost operator string1[0] uncontracted
  2304. return Add(*result)
  2305. def wicks(e, **kw_args):
  2306. """
  2307. Returns the normal ordered equivalent of an expression using Wicks Theorem.
  2308. Examples
  2309. ========
  2310. >>> from sympy import symbols, Dummy
  2311. >>> from sympy.physics.secondquant import wicks, F, Fd
  2312. >>> p, q, r = symbols('p,q,r')
  2313. >>> wicks(Fd(p)*F(q))
  2314. KroneckerDelta(_i, q)*KroneckerDelta(p, q) + NO(CreateFermion(p)*AnnihilateFermion(q))
  2315. By default, the expression is expanded:
  2316. >>> wicks(F(p)*(F(q)+F(r)))
  2317. NO(AnnihilateFermion(p)*AnnihilateFermion(q)) + NO(AnnihilateFermion(p)*AnnihilateFermion(r))
  2318. With the keyword 'keep_only_fully_contracted=True', only fully contracted
  2319. terms are returned.
  2320. By request, the result can be simplified in the following order:
  2321. -- KroneckerDelta functions are evaluated
  2322. -- Dummy variables are substituted consistently across terms
  2323. >>> p, q, r = symbols('p q r', cls=Dummy)
  2324. >>> wicks(Fd(p)*(F(q)+F(r)), keep_only_fully_contracted=True)
  2325. KroneckerDelta(_i, _q)*KroneckerDelta(_p, _q) + KroneckerDelta(_i, _r)*KroneckerDelta(_p, _r)
  2326. """
  2327. if not e:
  2328. return S.Zero
  2329. opts = {
  2330. 'simplify_kronecker_deltas': False,
  2331. 'expand': True,
  2332. 'simplify_dummies': False,
  2333. 'keep_only_fully_contracted': False
  2334. }
  2335. opts.update(kw_args)
  2336. # check if we are already normally ordered
  2337. if isinstance(e, NO):
  2338. if opts['keep_only_fully_contracted']:
  2339. return S.Zero
  2340. else:
  2341. return e
  2342. elif isinstance(e, FermionicOperator):
  2343. if opts['keep_only_fully_contracted']:
  2344. return S.Zero
  2345. else:
  2346. return e
  2347. # break up any NO-objects, and evaluate commutators
  2348. e = e.doit(wicks=True)
  2349. # make sure we have only one term to consider
  2350. e = e.expand()
  2351. if isinstance(e, Add):
  2352. if opts['simplify_dummies']:
  2353. return substitute_dummies(Add(*[ wicks(term, **kw_args) for term in e.args]))
  2354. else:
  2355. return Add(*[ wicks(term, **kw_args) for term in e.args])
  2356. # For Mul-objects we can actually do something
  2357. if isinstance(e, Mul):
  2358. # we don't want to mess around with commuting part of Mul
  2359. # so we factorize it out before starting recursion
  2360. c_part = []
  2361. string1 = []
  2362. for factor in e.args:
  2363. if factor.is_commutative:
  2364. c_part.append(factor)
  2365. else:
  2366. string1.append(factor)
  2367. n = len(string1)
  2368. # catch trivial cases
  2369. if n == 0:
  2370. result = e
  2371. elif n == 1:
  2372. if opts['keep_only_fully_contracted']:
  2373. return S.Zero
  2374. else:
  2375. result = e
  2376. else: # non-trivial
  2377. if isinstance(string1[0], BosonicOperator):
  2378. raise NotImplementedError
  2379. string1 = tuple(string1)
  2380. # recursion over higher order contractions
  2381. result = _get_contractions(string1,
  2382. keep_only_fully_contracted=opts['keep_only_fully_contracted'] )
  2383. result = Mul(*c_part)*result
  2384. if opts['expand']:
  2385. result = result.expand()
  2386. if opts['simplify_kronecker_deltas']:
  2387. result = evaluate_deltas(result)
  2388. return result
  2389. # there was nothing to do
  2390. return e
  2391. class PermutationOperator(Expr):
  2392. """
  2393. Represents the index permutation operator P(ij).
  2394. P(ij)*f(i)*g(j) = f(i)*g(j) - f(j)*g(i)
  2395. """
  2396. is_commutative = True
  2397. def __new__(cls, i, j):
  2398. i, j = sorted(map(sympify, (i, j)), key=default_sort_key)
  2399. obj = Basic.__new__(cls, i, j)
  2400. return obj
  2401. def get_permuted(self, expr):
  2402. """
  2403. Returns -expr with permuted indices.
  2404. Explanation
  2405. ===========
  2406. >>> from sympy import symbols, Function
  2407. >>> from sympy.physics.secondquant import PermutationOperator
  2408. >>> p,q = symbols('p,q')
  2409. >>> f = Function('f')
  2410. >>> PermutationOperator(p,q).get_permuted(f(p,q))
  2411. -f(q, p)
  2412. """
  2413. i = self.args[0]
  2414. j = self.args[1]
  2415. if expr.has(i) and expr.has(j):
  2416. tmp = Dummy()
  2417. expr = expr.subs(i, tmp)
  2418. expr = expr.subs(j, i)
  2419. expr = expr.subs(tmp, j)
  2420. return S.NegativeOne*expr
  2421. else:
  2422. return expr
  2423. def _latex(self, printer):
  2424. return "P(%s%s)" % self.args
  2425. def simplify_index_permutations(expr, permutation_operators):
  2426. """
  2427. Performs simplification by introducing PermutationOperators where appropriate.
  2428. Explanation
  2429. ===========
  2430. Schematically:
  2431. [abij] - [abji] - [baij] + [baji] -> P(ab)*P(ij)*[abij]
  2432. permutation_operators is a list of PermutationOperators to consider.
  2433. If permutation_operators=[P(ab),P(ij)] we will try to introduce the
  2434. permutation operators P(ij) and P(ab) in the expression. If there are other
  2435. possible simplifications, we ignore them.
  2436. >>> from sympy import symbols, Function
  2437. >>> from sympy.physics.secondquant import simplify_index_permutations
  2438. >>> from sympy.physics.secondquant import PermutationOperator
  2439. >>> p,q,r,s = symbols('p,q,r,s')
  2440. >>> f = Function('f')
  2441. >>> g = Function('g')
  2442. >>> expr = f(p)*g(q) - f(q)*g(p); expr
  2443. f(p)*g(q) - f(q)*g(p)
  2444. >>> simplify_index_permutations(expr,[PermutationOperator(p,q)])
  2445. f(p)*g(q)*PermutationOperator(p, q)
  2446. >>> PermutList = [PermutationOperator(p,q),PermutationOperator(r,s)]
  2447. >>> expr = f(p,r)*g(q,s) - f(q,r)*g(p,s) + f(q,s)*g(p,r) - f(p,s)*g(q,r)
  2448. >>> simplify_index_permutations(expr,PermutList)
  2449. f(p, r)*g(q, s)*PermutationOperator(p, q)*PermutationOperator(r, s)
  2450. """
  2451. def _get_indices(expr, ind):
  2452. """
  2453. Collects indices recursively in predictable order.
  2454. """
  2455. result = []
  2456. for arg in expr.args:
  2457. if arg in ind:
  2458. result.append(arg)
  2459. else:
  2460. if arg.args:
  2461. result.extend(_get_indices(arg, ind))
  2462. return result
  2463. def _choose_one_to_keep(a, b, ind):
  2464. # we keep the one where indices in ind are in order ind[0] < ind[1]
  2465. return min(a, b, key=lambda x: default_sort_key(_get_indices(x, ind)))
  2466. expr = expr.expand()
  2467. if isinstance(expr, Add):
  2468. terms = set(expr.args)
  2469. for P in permutation_operators:
  2470. new_terms = set()
  2471. on_hold = set()
  2472. while terms:
  2473. term = terms.pop()
  2474. permuted = P.get_permuted(term)
  2475. if permuted in terms | on_hold:
  2476. try:
  2477. terms.remove(permuted)
  2478. except KeyError:
  2479. on_hold.remove(permuted)
  2480. keep = _choose_one_to_keep(term, permuted, P.args)
  2481. new_terms.add(P*keep)
  2482. else:
  2483. # Some terms must get a second chance because the permuted
  2484. # term may already have canonical dummy ordering. Then
  2485. # substitute_dummies() does nothing. However, the other
  2486. # term, if it exists, will be able to match with us.
  2487. permuted1 = permuted
  2488. permuted = substitute_dummies(permuted)
  2489. if permuted1 == permuted:
  2490. on_hold.add(term)
  2491. elif permuted in terms | on_hold:
  2492. try:
  2493. terms.remove(permuted)
  2494. except KeyError:
  2495. on_hold.remove(permuted)
  2496. keep = _choose_one_to_keep(term, permuted, P.args)
  2497. new_terms.add(P*keep)
  2498. else:
  2499. new_terms.add(term)
  2500. terms = new_terms | on_hold
  2501. return Add(*terms)
  2502. return expr