oscillators.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. ######################################################
  2. #
  3. # Fock space Hamiltonian truncation for phi^4 theory in 2 dimensions
  4. # Authors: Slava Rychkov (slava.rychkov@lpt.ens.fr) and Lorenzo Vitale (lorenzo.vitale@epfl.ch)
  5. # December 2014
  6. #
  7. ######################################################
  8. import scipy
  9. from scipy import pi
  10. from numpy import product, sqrt
  11. from operator import attrgetter
  12. from statefuncs import omega, State, NotInBasis
  13. tol = 0.0001
  14. class NormalOrderedOperator():
  15. """ abstract class for normal ordered operator
  16. A normal-ordered operator is given by two lists of (Fourier) indices specifying
  17. which creation operators are present (clist) and which annihilation operators
  18. are present (dlist) and an overall multiplicative coefficient.
  19. Attributes:
  20. clist (list of ints): a list of ns (Fourier indices) corresponding
  21. to creation ops, see phi1234.py buildMatrix()
  22. dlist (list of ints): another list of ns corresponding to
  23. destruction ops
  24. L (float): circumference of the circle (the spatial dimension)
  25. m (float): mass of the field
  26. coeff (float): the overall multiplicative prefactor of this operator
  27. deltaE (float): the net energy difference produced by acting on a state
  28. with this operator
  29. """
  30. def __init__(self,clist,dlist,L,m,extracoeff=1):
  31. """
  32. Args:
  33. clist, dlist, L, m: as above
  34. extracoeff (float): an overall multiplicative prefactor for the
  35. operator, *written as a power of the field operator phi*
  36. """
  37. self.clist=clist
  38. self.dlist=dlist
  39. self.L=L
  40. self.m=m
  41. # coeff converts the overall prefactor of phi (extracoeff) to a prefactor
  42. # for the string of creation and annihilation operators in the final operator
  43. # see the normalization in Eq. 2.6
  44. self.coeff = extracoeff/product([sqrt(2.*L*omega(n,L,m)) for n in clist+dlist])
  45. #can this be sped up by vectorizing the omega function? IL
  46. self.deltaE = sum([omega(n,L,m) for n in clist]) - sum([omega(n,L,m) for n in dlist])
  47. #can perform this as a vector op but the speedup is small
  48. #self.deltaE = sum(omega(array(clist),L,m))-sum(omega(array(dlist),L,m))
  49. def __repr__(self):
  50. return str(self.clist)+" "+str(self.dlist)
  51. def _transformState(self, state0):
  52. """
  53. Applies the normal ordered operator to a given state.
  54. Args:
  55. state0 (State): an input state for this operator
  56. Returns:
  57. A tuple representing the input state after being acted on by
  58. the normal-ordered operator and any multiplicative factors
  59. from performing the commutations.
  60. Example:
  61. For a state with nmax=1 and state0.occs = [0,0,2]
  62. (2 excitations in the n=+1 mode, since counting starts at
  63. -nmax) if the operator is a_{k=1}, corresponding to
  64. clist = []
  65. dlist = [1]
  66. coeff = 1
  67. then this will return a state with occs [0,0,1] and a prefactor of
  68. 2 (for the two commutations).
  69. """
  70. #make a copy of this state up to occupation numbers and nmax
  71. state = State(state0.occs[:], state0.nmax, fast=True)
  72. n = 1.
  73. #for each of the destruction operators
  74. for i in self.dlist:
  75. #if there is no Fourier mode at that value of n (ground state)
  76. if state[i] == 0:
  77. #then the state is annihilated
  78. return(0,None)
  79. #otherwise we multiply n by the occupation number of that state
  80. n *= state[i]
  81. #and decrease its occupation number by 1
  82. state[i] -= 1
  83. #for each of the creation operators
  84. for i in self.clist:
  85. #multiply n by the occupation number of that state
  86. n *= state[i]+1
  87. #increase the occupation number of that mode by 1
  88. state[i] += 1
  89. return (n, state)
  90. def apply(self, basis, i, lookupbasis=None):
  91. """ Takes a state index in basis, returns another state index (if it
  92. belongs to the lookupbasis) and a proportionality coefficient. Otherwise raises NotInBasis.
  93. lookupbasis can be different from basis, but it's assumed that they have the same nmax"""
  94. if lookupbasis == None:
  95. lookupbasis = basis
  96. if self.deltaE+basis[i].energy < 0.-tol or self.deltaE+basis[i].energy > lookupbasis.Emax+tol:
  97. # The trasformed element surely does not belong to the basis if E>Emax or E<0
  98. raise NotInBasis()
  99. # apply the normal-order operator to this basis state
  100. n, newstate = self._transformState(basis[i])
  101. #if the state was annihilated by the operator, return (0, None)
  102. if n==0:
  103. return (0, None)
  104. # otherwise, look up this state in the lookup basis
  105. m, j = lookupbasis.lookup(newstate)
  106. c = 1.
  107. if basis[i].isParityEigenstate():
  108. c = 1/sqrt(2.)
  109. # Required for state normalization
  110. # return the overall proportionality and the state index
  111. return (m*c*sqrt(n)*self.coeff, j)