secondquant.py 88 KB

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