secondquant.py 89 KB

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