Beispiel #1
0
 def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc):
     # okay... we have the target eigensystem. We now still
     # need an operator EmbFock + vloc which generates it as
     # a ground state density. The condition here is that
     #
     #    dot(h0_for_vloc, vloc1)  =: K v
     #
     # has the same eigensystem as the one we're calculating,
     # or, equivalently, that it commutes with the rdm we have.
     # We assert that the resulting Fock matrix does not have
     # components mixing occupied and virtual orbitals, which is
     # equivalent.
     # Note that we cannot assume that F is diagonal in the target rdm
     # eigenvectors, because the eigensystem is degenerate
     # (has only 0 and 1 evs)
     #
     # Also note that in general vloc has not enough variational
     # freedom to represent arbitrary eigensystems, so technically we
     # are returning the best approximation which is possible.
     ew, ev = la.eigh(NewRdm)
     O, V = ev[:, nOcc:], ev[:, :nOcc]
     lhs = mdot(O.T, EmbFock, V).flatten()
     VlocSize = h0_for_vloc.shape[-1]
     h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb, nEmb, VlocSize))
     K = einsum("ro,rsp,sv->ovp", O, h0_for_vloc_reshape,
                V).reshape(O.shape[1] * V.shape[1], VlocSize)
     rhs = -la.lstsq(K, lhs)[0]
     return dot(h0_for_vloc_reshape, rhs)
Beispiel #2
0
def MakeFockOp(Rdm, CoreH, Int2e_Frs, ORB_OCC, Int2e_4ix=None, Orb=None, ExchFactor=1.):
   """make closed-shell/spin ensemble Fock matrix:
         f[rs] = h[rs] + j[rs] - .5 k[rs].
   where j[rs] = (rs|tu) rdm[tu]
   and   k[rs] = (rs|tu) rdm[su]
   Return (f, j, k)."""
   assert(Int2e_Frs is None or Int2e_4ix is None)
   if Int2e_Frs is not None:
      if Orb is None:
         OccNum,Orb = eigh(-Rdm); OccNum *= -1.
      else:
         OccNum = diag(mdot(Orb.T, Rdm, Orb))

      # filter out occupation numbers slightly broken due to rounding.
      OccNum[OccNum < 0.] = 0.
      OccNum[OccNum > ORB_OCC] = ORB_OCC

      nFit, nOrb = Int2e_Frs.shape[0], Int2e_Frs.shape[1]

      # make coulomb.
      gamma = einsum("Frs,rs",Int2e_Frs, Rdm)
      j = einsum("Frs,F",Int2e_Frs,gamma)

      # make exchange -- first need to find the occupied orbitals.
      nOcc = len([o for o in OccNum if abs(o-ORB_OCC)<1e-8])
      OccOrb = Orb[:,:nOcc] * OccNum[:nOcc]**.5
      k1 = einsum("Frs,si->Fir", Int2e_Frs, OccOrb).reshape((nFit * nOcc, nOrb))
      k = dot(k1.T, k1)
   else:
      assert(Int2e_4ix is not None)
      j = einsum("rstu,tu",Int2e_4ix, Rdm)
      k = einsum("rtsu,tu",Int2e_4ix, Rdm)
   Fock = CoreH + j - (ExchFactor/ORB_OCC) * k
   return Fock, j, k
Beispiel #3
0
 def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc):
    # okay... we have the target eigensystem. We now still
    # need an operator EmbFock + vloc which generates it as
    # a ground state density. The condition here is that
    #
    #    dot(h0_for_vloc, vloc1)  =: K v
    #
    # has the same eigensystem as the one we're calculating,
    # or, equivalently, that it commutes with the rdm we have.
    # We assert that the resulting Fock matrix does not have
    # components mixing occupied and virtual orbitals, which is
    # equivalent.
    # Note that we cannot assume that F is diagonal in the target rdm
    # eigenvectors, because the eigensystem is degenerate
    # (has only 0 and 1 evs)
    #
    # Also note that in general vloc has not enough variational
    # freedom to represent arbitrary eigensystems, so technically we
    # are returning the best approximation which is possible.
    ew,ev = la.eigh(NewRdm)
    O,V = ev[:,nOcc:], ev[:,:nOcc]
    lhs = mdot(O.T,EmbFock,V).flatten()
    VlocSize = h0_for_vloc.shape[-1]
    h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb,nEmb,VlocSize))
    K = einsum("ro,rsp,sv->ovp",O,h0_for_vloc_reshape,V).reshape(O.shape[1]*V.shape[1],VlocSize)
    rhs = -la.lstsq(K,lhs)[0]
    return dot(h0_for_vloc_reshape,rhs)
Beispiel #4
0
      def RunVcorUpdate(VcorLarge):
         #assert(np.allclose(VcorLarge[1::2, ::2],0.))
         #assert(np.allclose(VcorLarge[ ::2,1::2],0.))
         with Log.Section("lmf","FULL SYSTEM -- MEAN FIELD CALCULATION", 1):
            #vFock = self.FullSystem.FockT[0] - self.FullSystem.CoreH[0]
            self.FullSystem.CoreH[0] = FullCoreH_Unpatched[0] + VcorLarge
            #self.FullSystem.FockT[0] = self.FullSystem.CoreH[0] + vFock
            self.FullSystem.FockT[0] = FullCoreH_Unpatched[0] + VcorLarge
            # ^- this adds the changed vloc also to the FockT initial guess.
            #    required if iterations are disabled.
            FullSystemHfResult = self.FullSystem._RunHf(Log=Log)
            FullSystemHfResult = self.FullSystem

         jgr = self.RunFragments(FullSystemHfResult, Log)
         jgr.MeanFieldEnergy = FullSystemHfResult.MeanFieldEnergy
         jgr.TotalEnergy = jgr.TotalElecEnergy + self.FullSystem.CoreEnergy
         self.FitCorrelationPotentials(jgr, FullSystemHfResult, PrintEmb)

         # now: add changed potentials to large system, and run again.
         dVcorLarge = np.zeros(VcorLarge.shape)
         assert(g.VcorType == "Local" or g.VcorType == "Diagonal")
         for (Fragment, VcorFull) in zip(self.Fragments, jgr.FragmentPotentials):
            nImp = len(Fragment.Sites)
            Vcor = Fragment.Factor * VcorFull[:nImp,:nImp]
            for Replica in Fragment.Replicas:
               VcorR = mdot(Replica.Trafo, Vcor, Replica.Trafo.T)
               E = list(enumerate(Replica.Sites))
               for (i,iSite),(j,jSite) in it.product(E,E):
                  dVcorLarge[iSite,jSite] += VcorR[i,j]

         return dVcorLarge, jgr, FullSystemHfResult
Beispiel #5
0
      def RunVcorUpdate(VcorLarge):
         #assert(np.allclose(VcorLarge[1::2, ::2],0.))
         #assert(np.allclose(VcorLarge[ ::2,1::2],0.))
         with Log.Section("lmf","FULL SYSTEM -- MEAN FIELD CALCULATION", 1):
            #vFock = self.FullSystem.FockT[0] - self.FullSystem.CoreH[0]
            self.FullSystem.CoreH[0] = FullCoreH_Unpatched[0] + VcorLarge
            #self.FullSystem.FockT[0] = self.FullSystem.CoreH[0] + vFock
            self.FullSystem.FockT[0] = FullCoreH_Unpatched[0] + VcorLarge
            # ^- this adds the changed vloc also to the FockT initial guess.
            #    required if iterations are disabled.
            FullSystemHfResult = self.FullSystem._RunHf(Log=Log)
            FullSystemHfResult = self.FullSystem

         jgr = self.RunFragments(FullSystemHfResult, Log)
         jgr.MeanFieldEnergy = FullSystemHfResult.MeanFieldEnergy
         jgr.TotalEnergy = jgr.TotalElecEnergy + self.FullSystem.CoreEnergy
         self.FitCorrelationPotentials(jgr, FullSystemHfResult, PrintEmb)

         # now: add changed potentials to large system, and run again.
         dVcorLarge = np.zeros(VcorLarge.shape)
         assert(g.VcorType == "Local" or g.VcorType == "Diagonal")
         for (Fragment, VcorFull) in zip(self.Fragments, jgr.FragmentPotentials):
            nImp = len(Fragment.Sites)
            Vcor = Fragment.Factor * VcorFull[:nImp,:nImp]
            for Replica in Fragment.Replicas:
               VcorR = mdot(Replica.Trafo, Vcor, Replica.Trafo.T)
               E = list(enumerate(Replica.Sites))
               for (i,iSite),(j,jSite) in it.product(E,E):
                  dVcorLarge[iSite,jSite] += VcorR[i,j]

         return dVcorLarge, jgr, FullSystemHfResult
Beispiel #6
0
    def TransformToEmb(self, OrbL, InpT, OrbR):
        """return Op[k,l] = OrbL[r,k]^* Op[r,s] OrbR[s,l], where
      Op: T x U x U is a periodically symmetric operator expressed
      in the super-cell x unit-cell basis, and OrbL/OrbR are one-particle
      transformations with the super-cell basis as row dimension."""
        nSitesU, nSitesS = self.nSitesU, self.nSites
        assert (InpT.shape == (self.nUnitCells, nSitesU, nSitesU)
                or InpT.shape == (nSitesS, nSitesU))
        assert (OrbL.shape[0] == nSitesS and OrbR.shape[0] == nSitesS)
        Op = InpT.reshape((self.nUnitCells, nSitesU, nSitesU))

        def FindRequiredTs(Op):
            # make a list of Ts we need to consider in the transformation.
            # if Op[iT,:,:] is zero, then we can skip the T.
            iTs = []
            for iT in range(self.nUnitCells):
                if not np.allclose(Op[iT, :, :], 0.):
                    iTs.append(iT)
            return np.array(iTs)

        iOpTs = FindRequiredTs(Op)
        #print "iTs with support: %i of %i:  %s" % (len(iOpTs), self.nUnitCells, iOpTs)

        Out = np.zeros((OrbL.shape[1], OrbR.shape[1]), Op.dtype)
        if len(iOpTs) >= .3 * self.nUnitCells:
            Op = InpT.reshape((nSitesS, nSitesU))
            for (i, ijk) in enumerate(self.iTs):
                RowI = self._ConstructTranslatedRows(Op, ijk).T
                # ^- that's the Op[nSitesU*i:nSitesU*(i+1),:] subset of the
                #    operator expressed in the full nSitesS x nSitesS basis.
                #    (see FSuperCell._ExpandFull)
                Out += mdot(np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :].T),
                            RowI, OrbR)
        elif 1:
            Op = Op[iOpTs, :, :]
            OrbR = OrbR.reshape((self.nUnitCells, nSitesU, OrbR.shape[1]))
            for (i, ijk) in enumerate(self.iTs):
                PF, I = self._MakeUnitCellPhasesForT_Restricted(ijk, iOpTs)
                RowIR = np.einsum("t,trs,trl->sl", PF, Op, OrbR[I, :, :])
                Out += np.einsum(
                    "rk,rl->kl",
                    np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :]), RowIR)
        else:
            nT = len(iOpTs)
            Op = Op[iOpTs, :, :].reshape((nT * nSitesU, nSitesU))
            nOrbR = OrbR.shape[1]
            OrbR = OrbR.reshape((self.nUnitCells, nSitesU, nOrbR))
            PermShape = (nT * nSitesU, nOrbR)
            PfShape = (nT, 1, 1)
            for (i, ijk) in enumerate(self.iTs):
                PF, I = self._MakeUnitCellPhasesForT_Restricted(ijk, iOpTs)
                RowIR = np.dot(Op.T, (PF.reshape(PfShape) *
                                      OrbR[I, :, :]).reshape(PermShape))
                Out += np.dot(
                    np.conj(OrbL[nSitesU * i:nSitesU * (i + 1), :].T), RowIR)
        return Out
Beispiel #7
0
   def TransformToEmb(self, OrbL, InpT, OrbR):
      """return Op[k,l] = OrbL[r,k]^* Op[r,s] OrbR[s,l], where
      Op: T x U x U is a periodically symmetric operator expressed
      in the super-cell x unit-cell basis, and OrbL/OrbR are one-particle
      transformations with the super-cell basis as row dimension."""
      nSitesU, nSitesS = self.nSitesU, self.nSites
      assert(InpT.shape == (self.nUnitCells, nSitesU, nSitesU) or
             InpT.shape == (nSitesS, nSitesU))
      assert(OrbL.shape[0] == nSitesS and OrbR.shape[0] == nSitesS)
      Op = InpT.reshape((self.nUnitCells, nSitesU, nSitesU))
      def FindRequiredTs(Op):
         # make a list of Ts we need to consider in the transformation.
         # if Op[iT,:,:] is zero, then we can skip the T.
         iTs = []
         for iT in range(self.nUnitCells):
            if not np.allclose(Op[iT,:,:], 0.):
               iTs.append(iT)
         return np.array(iTs)
      iOpTs = FindRequiredTs(Op)
      #print "iTs with support: %i of %i:  %s" % (len(iOpTs), self.nUnitCells, iOpTs)

      Out = np.zeros((OrbL.shape[1],OrbR.shape[1]),Op.dtype)
      if len(iOpTs) >= .3 * self.nUnitCells:
         Op = InpT.reshape((nSitesS, nSitesU))
         for (i,ijk) in enumerate(self.iTs):
            RowI = self._ConstructTranslatedRows(Op, ijk).T
            # ^- that's the Op[nSitesU*i:nSitesU*(i+1),:] subset of the
            #    operator expressed in the full nSitesS x nSitesS basis.
            #    (see FSuperCell._ExpandFull)
            Out += mdot(np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:].T),
                        RowI, OrbR)
      elif 0:
         Op = Op[iOpTs,:,:]
         OrbR = OrbR.reshape((self.nUnitCells, nSitesU, OrbR.shape[1]))
         for (i,ijk) in enumerate(self.iTs):
            PF,I = self._MakeUnitCellPhasesForT_Restricted(ijk,iOpTs)
            RowIR = np.einsum("t,trs,trl->sl",PF,Op,OrbR[I,:,:])
            Out += np.einsum("rk,rl->kl",np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:]), RowIR)
      else:
         nT = len(iOpTs)
         Op = Op[iOpTs,:,:].reshape((nT*nSitesU,nSitesU))
         nOrbR = OrbR.shape[1]
         OrbR = OrbR.reshape((self.nUnitCells, nSitesU, nOrbR))
         PermShape = (nT*nSitesU,nOrbR)
         PfShape = (nT,1,1)
         for (i,ijk) in enumerate(self.iTs):
            PF,I = self._MakeUnitCellPhasesForT_Restricted(ijk,iOpTs)
            RowIR = np.dot(Op.T, (PF.reshape(PfShape)*OrbR[I,:,:]).reshape(PermShape))
            Out += np.dot(np.conj(OrbL[nSitesU*i:nSitesU*(i+1),:].T), RowIR)
      return Out
Beispiel #8
0
        def MakeIdempotentApproxRdm(TargetRdm):
            # make a idempotent density matrix which exactly
            # coincides with TargetRdm on the imp x imp subset.
            A = TargetRdm[:nImp, :nImp]
            C = TargetRdm[nImp:, nImp:]
            assert (A.shape == C.shape)
            C = np.eye(A.shape[0]) - A

            # ^-
            # WARNING: at this moment this does assume that the embedding
            #   basis is constructed as full Smh basis, i.e., that the hole
            #   state corresponding to imp site i is at nImp + i. For other
            #   cases we need additional rotations on C (not simply overwrite
            #   it) and fix the eigenvalues in some other way.
            def MakeRho(A, B, C):
                return np.vstack(
                    [np.hstack([A, B]),
                     np.hstack([np.conj(B.T), C])])

            L = nImp
            ewA, evA = la.eigh(A)
            ewC, evC = la.eigh(C)
            basis = MakeRho(evA, zeros_like(A), evC)
            R = mdot(basis.T, TargetRdm, basis)
            M = 0. * basis
            M[:L, :L] = diag(ewA)
            M[L:, L:] = diag(ewC)
            ewB = (ewA - ewA**2)**.5
            # ^- we can still put in random phases here and retain an
            #    idempotent target matrix. we get them from the
            #    transformation of the target density matrix, hopefully
            #    in such a way that also the off-diagonals are not way off,
            #    even if we are only fitting on ImpRdm instead of FullRdm.
            #    (see idempotency_gen.py)
            #
            #    This freedom may be related to the freedom in choosing orbital
            #    occupation.
            ewB_ref = np.diag(R[nImp:, :nImp][::-1, :])
            ewB *= np.sign(ewB_ref)
            M[L:, :L] = np.diag(ewB)[::-1, :]
            M[:L, L:] = np.conj(M[L:, :L]).T
            rho = dot(basis, np.dot(M, basis.T))
            assert (np.allclose(np.dot(rho, rho) - rho, 0.0))
            # ^- will work for HF in HF, but not for FCI in HF
            return rho
Beispiel #9
0
      def MakeIdempotentApproxRdm(TargetRdm):
         # make a idempotent density matrix which exactly
         # coincides with TargetRdm on the imp x imp subset.
         A = TargetRdm[:nImp,:nImp]
         C = TargetRdm[nImp:,nImp:]
         assert(A.shape == C.shape)
         C = np.eye(A.shape[0]) - A
         # ^-
         # WARNING: at this moment this does assume that the embedding
         #   basis is constructed as full Smh basis, i.e., that the hole
         #   state corresponding to imp site i is at nImp + i. For other
         #   cases we need additional rotations on C (not simply overwrite
         #   it) and fix the eigenvalues in some other way.
         def MakeRho(A,B,C):
            return np.vstack([np.hstack([A,B]),np.hstack([np.conj(B.T),C])])

         L = nImp
         ewA,evA = la.eigh(A)
         ewC,evC = la.eigh(C)
         basis = MakeRho(evA,zeros_like(A),evC)
         R = mdot(basis.T, TargetRdm, basis)
         M = 0.*basis
         M[:L,:L] = diag(ewA)
         M[L:,L:] = diag(ewC)
         ewB = (ewA - ewA**2)**.5
         # ^- we can still put in random phases here and retain an
         #    idempotent target matrix. we get them from the
         #    transformation of the target density matrix, hopefully
         #    in such a way that also the off-diagonals are not way off,
         #    even if we are only fitting on ImpRdm instead of FullRdm.
         #    (see idempotency_gen.py)
         #
         #    This freedom may be related to the freedom in choosing orbital
         #    occupation.
         ewB_ref = np.diag(R[nImp:,:nImp][::-1,:])
         ewB *= np.sign(ewB_ref)
         M[L:,:L] = np.diag(ewB)[::-1,:]
         M[:L,L:] = np.conj(M[L:,:L]).T
         rho = dot(basis,np.dot(M,basis.T))
         assert(np.allclose(np.dot(rho,rho)-rho,0.0))
         # ^- will work for HF in HF, but not for FCI in HF
         return rho
Beispiel #10
0
   def GetImpRdmFitAnalytical(RdmHl, nImp, VLOC_TYPE, VLOC_FIT_TYPE):
      # this does the same as resmin, but
      # solves the target fitting equation analyically.
      # note that we can setup an equivalent routine for fullrdm fit.
      assert(VLOC_TYPE == "Local")
      # ^- we could do Diagonal/ImpRdm by making an idempotent
      # approximation to a RDM obtained by taking the previous HF
      # RDM and just fixing the diagonal entries to the CI RDM.

      def MakeIdempotentApproxRdm(TargetRdm):
         # make a idempotent density matrix which exactly
         # coincides with TargetRdm on the imp x imp subset.
         A = TargetRdm[:nImp,:nImp]
         C = TargetRdm[nImp:,nImp:]
         assert(A.shape == C.shape)
         C = np.eye(A.shape[0]) - A
         # ^-
         # WARNING: at this moment this does assume that the embedding
         #   basis is constructed as full Smh basis, i.e., that the hole
         #   state corresponding to imp site i is at nImp + i. For other
         #   cases we need additional rotations on C (not simply overwrite
         #   it) and fix the eigenvalues in some other way.
         def MakeRho(A,B,C):
            return np.vstack([np.hstack([A,B]),np.hstack([np.conj(B.T),C])])

         L = nImp
         ewA,evA = la.eigh(A)
         ewC,evC = la.eigh(C)
         basis = MakeRho(evA,zeros_like(A),evC)
         R = mdot(basis.T, TargetRdm, basis)
         M = 0.*basis
         M[:L,:L] = diag(ewA)
         M[L:,L:] = diag(ewC)
         ewB = (ewA - ewA**2)**.5
         # ^- we can still put in random phases here and retain an
         #    idempotent target matrix. we get them from the
         #    transformation of the target density matrix, hopefully
         #    in such a way that also the off-diagonals are not way off,
         #    even if we are only fitting on ImpRdm instead of FullRdm.
         #    (see idempotency_gen.py)
         #
         #    This freedom may be related to the freedom in choosing orbital
         #    occupation.
         ewB_ref = np.diag(R[nImp:,:nImp][::-1,:])
         ewB *= np.sign(ewB_ref)
         M[L:,:L] = np.diag(ewB)[::-1,:]
         M[:L,L:] = np.conj(M[L:,:L]).T
         rho = dot(basis,np.dot(M,basis.T))
         assert(np.allclose(np.dot(rho,rho)-rho,0.0))
         # ^- will work for HF in HF, but not for FCI in HF
         return rho

      def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc):
         # okay... we have the target eigensystem. We now still
         # need an operator EmbFock + vloc which generates it as
         # a ground state density. The condition here is that
         #
         #    dot(h0_for_vloc, vloc1)  =: K v
         #
         # has the same eigensystem as the one we're calculating,
         # or, equivalently, that it commutes with the rdm we have.
         # We assert that the resulting Fock matrix does not have
         # components mixing occupied and virtual orbitals, which is
         # equivalent.
         # Note that we cannot assume that F is diagonal in the target rdm
         # eigenvectors, because the eigensystem is degenerate
         # (has only 0 and 1 evs)
         #
         # Also note that in general vloc has not enough variational
         # freedom to represent arbitrary eigensystems, so technically we
         # are returning the best approximation which is possible.
         ew,ev = la.eigh(NewRdm)
         O,V = ev[:,nOcc:], ev[:,:nOcc]
         lhs = mdot(O.T,EmbFock,V).flatten()
         VlocSize = h0_for_vloc.shape[-1]
         h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb,nEmb,VlocSize))
         K = einsum("ro,rsp,sv->ovp",O,h0_for_vloc_reshape,V).reshape(O.shape[1]*V.shape[1],VlocSize)
         rhs = -la.lstsq(K,lhs)[0]
         return dot(h0_for_vloc_reshape,rhs)

      # get number of orbitals we need to occupy in embedded HF.
      fOcc = np.trace(RdmHl)
      nOcc = int(fOcc+.5)
      assert(abs(fOcc - nOcc) < 1e-8)

      if VLOC_FIT_TYPE == "ImpRdm":
         # make an idempotent density matrix which exactly
         # coincides with RdmHl on the Imp x Imp part.
         FitRdmHf = MakeIdempotentApproxRdm(RdmHl)
      elif VLOC_FIT_TYPE == "FullRdm":
         # make the best idempotent approximation to the FCI
         # RDM. That's simply the matrix with the same natural
         # orbitals, but all occupation numbers rounded to 0
         # (if < .5) or 1 (if > .5).
         if 0:
            OccNum,NatOrb = la.eigh(-RdmHl); OccNum *= -1.
            OccNumHf = zeros_like(OccNum)
            OccNumHf[:nOcc] = 1.
            FitRdmHf = mdot(NatOrb, diag(OccNumHf), NatOrb.T)

         # ^- okay.. that is not *entirely* right:
         #  here we first approximate the target RDM, and then
         #  approximate the potential changes required to most
         #  closely obtain the target RDM as a HF solution.
         FitRdmHf = RdmHl
      else:
         # not supported.
         assert(0)
      def TestMakeVlocForRdm():
         vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
         NewF = EmbFock + vloc
         ew,ev = la.eigh(NewF)
         TestRdm = mdot(ev[:,:nOcc], ev[:,:nOcc].T)
         print TestRdm-FitRdmHf
      return MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
Beispiel #11
0
 def TestMakeVlocForRdm():
    vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
    NewF = EmbFock + vloc
    ew,ev = la.eigh(NewF)
    TestRdm = mdot(ev[:,:nOcc], ev[:,:nOcc].T)
    print TestRdm-FitRdmHf
Beispiel #12
0
    def GetImpRdmFitAnalytical(RdmHl, nImp, VLOC_TYPE, VLOC_FIT_TYPE):
        # this does the same as resmin, but
        # solves the target fitting equation analyically.
        # note that we can setup an equivalent routine for fullrdm fit.
        assert (VLOC_TYPE == "Local")

        # ^- we could do Diagonal/ImpRdm by making an idempotent
        # approximation to a RDM obtained by taking the previous HF
        # RDM and just fixing the diagonal entries to the CI RDM.

        def MakeIdempotentApproxRdm(TargetRdm):
            # make a idempotent density matrix which exactly
            # coincides with TargetRdm on the imp x imp subset.
            A = TargetRdm[:nImp, :nImp]
            C = TargetRdm[nImp:, nImp:]
            assert (A.shape == C.shape)
            C = np.eye(A.shape[0]) - A

            # ^-
            # WARNING: at this moment this does assume that the embedding
            #   basis is constructed as full Smh basis, i.e., that the hole
            #   state corresponding to imp site i is at nImp + i. For other
            #   cases we need additional rotations on C (not simply overwrite
            #   it) and fix the eigenvalues in some other way.
            def MakeRho(A, B, C):
                return np.vstack(
                    [np.hstack([A, B]),
                     np.hstack([np.conj(B.T), C])])

            L = nImp
            ewA, evA = la.eigh(A)
            ewC, evC = la.eigh(C)
            basis = MakeRho(evA, zeros_like(A), evC)
            R = mdot(basis.T, TargetRdm, basis)
            M = 0. * basis
            M[:L, :L] = diag(ewA)
            M[L:, L:] = diag(ewC)
            ewB = (ewA - ewA**2)**.5
            # ^- we can still put in random phases here and retain an
            #    idempotent target matrix. we get them from the
            #    transformation of the target density matrix, hopefully
            #    in such a way that also the off-diagonals are not way off,
            #    even if we are only fitting on ImpRdm instead of FullRdm.
            #    (see idempotency_gen.py)
            #
            #    This freedom may be related to the freedom in choosing orbital
            #    occupation.
            ewB_ref = np.diag(R[nImp:, :nImp][::-1, :])
            ewB *= np.sign(ewB_ref)
            M[L:, :L] = np.diag(ewB)[::-1, :]
            M[:L, L:] = np.conj(M[L:, :L]).T
            rho = dot(basis, np.dot(M, basis.T))
            assert (np.allclose(np.dot(rho, rho) - rho, 0.0))
            # ^- will work for HF in HF, but not for FCI in HF
            return rho

        def MakeVlocForRdm(NewRdm, nOcc, EmbFock, h0_for_vloc):
            # okay... we have the target eigensystem. We now still
            # need an operator EmbFock + vloc which generates it as
            # a ground state density. The condition here is that
            #
            #    dot(h0_for_vloc, vloc1)  =: K v
            #
            # has the same eigensystem as the one we're calculating,
            # or, equivalently, that it commutes with the rdm we have.
            # We assert that the resulting Fock matrix does not have
            # components mixing occupied and virtual orbitals, which is
            # equivalent.
            # Note that we cannot assume that F is diagonal in the target rdm
            # eigenvectors, because the eigensystem is degenerate
            # (has only 0 and 1 evs)
            #
            # Also note that in general vloc has not enough variational
            # freedom to represent arbitrary eigensystems, so technically we
            # are returning the best approximation which is possible.
            ew, ev = la.eigh(NewRdm)
            O, V = ev[:, nOcc:], ev[:, :nOcc]
            lhs = mdot(O.T, EmbFock, V).flatten()
            VlocSize = h0_for_vloc.shape[-1]
            h0_for_vloc_reshape = h0_for_vloc.reshape((nEmb, nEmb, VlocSize))
            K = einsum("ro,rsp,sv->ovp", O, h0_for_vloc_reshape,
                       V).reshape(O.shape[1] * V.shape[1], VlocSize)
            rhs = -la.lstsq(K, lhs)[0]
            return dot(h0_for_vloc_reshape, rhs)

        # get number of orbitals we need to occupy in embedded HF.
        fOcc = np.trace(RdmHl)
        nOcc = int(fOcc + .5)
        assert (abs(fOcc - nOcc) < 1e-8)

        if VLOC_FIT_TYPE == "ImpRdm":
            # make an idempotent density matrix which exactly
            # coincides with RdmHl on the Imp x Imp part.
            FitRdmHf = MakeIdempotentApproxRdm(RdmHl)
        elif VLOC_FIT_TYPE == "FullRdm":
            # make the best idempotent approximation to the FCI
            # RDM. That's simply the matrix with the same natural
            # orbitals, but all occupation numbers rounded to 0
            # (if < .5) or 1 (if > .5).
            if 0:
                OccNum, NatOrb = la.eigh(-RdmHl)
                OccNum *= -1.
                OccNumHf = zeros_like(OccNum)
                OccNumHf[:nOcc] = 1.
                FitRdmHf = mdot(NatOrb, diag(OccNumHf), NatOrb.T)

            # ^- okay.. that is not *entirely* right:
            #  here we first approximate the target RDM, and then
            #  approximate the potential changes required to most
            #  closely obtain the target RDM as a HF solution.
            FitRdmHf = RdmHl
        else:
            # not supported.
            assert (0)

        def TestMakeVlocForRdm():
            vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
            NewF = EmbFock + vloc
            ew, ev = la.eigh(NewF)
            TestRdm = mdot(ev[:, :nOcc], ev[:, :nOcc].T)
            print TestRdm - FitRdmHf

        return MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
Beispiel #13
0
 def TestMakeVlocForRdm():
     vloc = MakeVlocForRdm(FitRdmHf, nOcc, EmbFock, h0_for_vloc)
     NewF = EmbFock + vloc
     ew, ev = la.eigh(NewF)
     TestRdm = mdot(ev[:, :nOcc], ev[:, :nOcc].T)
     print TestRdm - FitRdmHf
Beispiel #14
0
 def GetRdm(self):
    #return 2.0 * dot(self.Orbs[:,:nOcc], self.Orbs[:,:nOcc].T)
    return mdot(self.Orbs, diag(self.OccNumbers), self.Orbs.T)
Beispiel #15
0
def _TestSuperCells():
   from numpy import set_printoptions, nan
   set_printoptions(precision=5,linewidth=10060,suppress=True,threshold=nan)
   if 1:
      L = 12
      nImp = 1
      Hub1d = FHubbardModel1d(nImp, {'t': 1., 'U': 4.})
      sc = FSuperCell(Hub1d, [L/nImp], [-1])
      sc = FSuperCell(Hub1d, [L/nImp], [np.exp(.221j)])
      #sc = FSuperCell(Hub1d, [L/nImp], [1])
   else:
      #Lx,Ly = 320,120
      # ^- FIXME: putting lots of sites there crashes the program. (out of memory)
      #nImpX,nImpY = 2,1
      PhaseShift = None

      FCls = FTestModel2d
      #FCls = FHubbardModel2dSquare

      Lx,Ly=4,3
      #PhaseShift=[-1.,-1.]   # anti-periodic boundary conditions
      PhaseShift=[1.,1.]     # periodic boundary conditions
      PhaseShift=[np.exp(.2j),np.exp(-.72j)] # wtf-like boundary conditions
      nImpX,nImpY = 2,1
      #nImpX,nImpY = 1,1
      nImp = nImpX * nImpY
      Hub2dSq = FCls((nImpX,nImpY), {'t': 1., 'U': 4.})
      sc = FSuperCell(Hub2dSq, [Lx/nImpX,Ly/nImpY], PhaseShift)
   #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None)
   #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None)
   CoreH = sc.MakeTijMatrix()
   #print "CoreH via super cells:\n%s" % repr(CoreH)
   print "CoreH spectrum:\n%s" % la.eigh(CoreH)[0]

   #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), (0,0))
   #print "RealSpaceOrb k == (0,0):\n%s" % Orb
   #print "norm(orb) == ", la.norm(Orb)
   SymBasis = np.hstack([sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk) for ijk in sc.iKs])
   print "symmetry adapted basis:\n%s" % SymBasis
   #print "sc.nUnitCells = ", sc.nUnitCells
   #print "sc.nSites = ", sc.nSites
   #print "SymBasis.shape = ", SymBasis.shape
   print "norm( dot(conj(SymBasis.T),SymBasis) - eye(nSites) ): %s" % (la.norm( np.dot(np.conj(SymBasis.T),SymBasis) - np.eye(sc.nSites) ))

   print "CoreH via super cells:\n%s" % CoreH
   print "CoreH in symmetry basis:\n%s" % (mdot(np.conj(SymBasis.T), CoreH, SymBasis))
   #print "CoreH -- 1site transformed:\n%s" % (mdot(CoreH, SymBasis))
   nSitesS = SymBasis.shape[1]
   nSitesU = nImp
   nUnitCells = nSitesS/nSitesU
   CoreH_K = sc.TransformToK(CoreH[:nSitesS,:nSitesU])
   print "And via .TransformToK:\n%s" % CoreH_K
   CoreH_SymUqBt = sc.TransformToT(CoreH_K)
   print "...back to t-space:\n%s" % CoreH_SymUqBt
   print "difference norm to orig: %.2e" % la.norm(CoreH_SymUqBt - CoreH[:nSitesS,:nSitesU])
   raise SystemExit
   #raise Exception("^- that does not look very diagonal (note: works with pbc and apbc, in both directions)")

   nSitesU = len(sc.Model.UnitCell)
   nSitesS = len(sc.Sites)
   #for ijk in sc.iKs.T:
      #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk)
      #print "ev x evT for ijk = %s:\n%s" % (ijk, np.dot(Orb,np.conj(Orb.T)))
   CoreH_SymUq = CoreH[:nSitesU,:nSitesS]
   print "symmetry unique part of CoreH:\n%s" % CoreH_SymUq
   CoreH_R = np.zeros((nSitesS,nSitesS),complex)
   for (i,ijk) in enumerate(sc.iTs.T):
      CoreH_R[nSitesU*i:nSitesU*(i+1),:] = sc._ConstructTranslatedRows(CoreH_SymUq, ijk)
   print "CoreH orig:\n%s" % CoreH
   print "CoreH reconstructed:\n%s" % CoreH_R
   print "difference norm to orig: %.2e" % la.norm(CoreH_R - CoreH)
Beispiel #16
0
def _TestSuperCells():
    from numpy import set_printoptions, nan
    set_printoptions(precision=5,
                     linewidth=10060,
                     suppress=True,
                     threshold=nan)
    if 1:
        L = 12
        nImp = 1
        Hub1d = FHubbardModel1d(nImp, {'t': 1., 'U': 4.})
        sc = FSuperCell(Hub1d, [L / nImp], [-1])
        sc = FSuperCell(Hub1d, [L / nImp], [np.exp(.221j)])
        #sc = FSuperCell(Hub1d, [L/nImp], [1])
    else:
        #Lx,Ly = 320,120
        # ^- FIXME: putting lots of sites there crashes the program. (out of memory)
        #nImpX,nImpY = 2,1
        PhaseShift = None

        FCls = FTestModel2d
        #FCls = FHubbardModel2dSquare

        Lx, Ly = 4, 3
        #PhaseShift=[-1.,-1.]   # anti-periodic boundary conditions
        PhaseShift = [1., 1.]  # periodic boundary conditions
        PhaseShift = [np.exp(.2j),
                      np.exp(-.72j)]  # wtf-like boundary conditions
        nImpX, nImpY = 2, 1
        #nImpX,nImpY = 1,1
        nImp = nImpX * nImpY
        Hub2dSq = FCls((nImpX, nImpY), {'t': 1., 'U': 4.})
        sc = FSuperCell(Hub2dSq, [Lx / nImpX, Ly / nImpY], PhaseShift)
    #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None)
    #sc = FSuperCell(Hub1d, [L/nImp,L/nImp], None)
    CoreH = sc.MakeTijMatrix()
    #print "CoreH via super cells:\n%s" % repr(CoreH)
    print "CoreH spectrum:\n%s" % la.eigh(CoreH)[0]

    #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), (0,0))
    #print "RealSpaceOrb k == (0,0):\n%s" % Orb
    #print "norm(orb) == ", la.norm(Orb)
    SymBasis = np.hstack([
        sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk)
        for ijk in sc.iKs
    ])
    print "symmetry adapted basis:\n%s" % SymBasis
    #print "sc.nUnitCells = ", sc.nUnitCells
    #print "sc.nSites = ", sc.nSites
    #print "SymBasis.shape = ", SymBasis.shape
    print "norm( dot(conj(SymBasis.T),SymBasis) - eye(nSites) ): %s" % (
        la.norm(np.dot(np.conj(SymBasis.T), SymBasis) - np.eye(sc.nSites)))

    print "CoreH via super cells:\n%s" % CoreH
    print "CoreH in symmetry basis:\n%s" % (mdot(np.conj(SymBasis.T), CoreH,
                                                 SymBasis))
    #print "CoreH -- 1site transformed:\n%s" % (mdot(CoreH, SymBasis))
    nSitesS = SymBasis.shape[1]
    nSitesU = nImp
    nUnitCells = nSitesS / nSitesU
    CoreH_K = sc.TransformToK(CoreH[:nSitesS, :nSitesU])
    print "And via .TransformToK:\n%s" % CoreH_K
    CoreH_SymUqBt = sc.TransformToT(CoreH_K)
    print "...back to t-space:\n%s" % CoreH_SymUqBt
    print "difference norm to orig: %.2e" % la.norm(CoreH_SymUqBt -
                                                    CoreH[:nSitesS, :nSitesU])
    raise SystemExit
    #raise Exception("^- that does not look very diagonal (note: works with pbc and apbc, in both directions)")

    nSitesU = len(sc.Model.UnitCell)
    nSitesS = len(sc.Sites)
    #for ijk in sc.iKs.T:
    #Orb = sc._MakeRealspaceOrb(np.eye(len(sc.Model.UnitCell)), ijk)
    #print "ev x evT for ijk = %s:\n%s" % (ijk, np.dot(Orb,np.conj(Orb.T)))
    CoreH_SymUq = CoreH[:nSitesU, :nSitesS]
    print "symmetry unique part of CoreH:\n%s" % CoreH_SymUq
    CoreH_R = np.zeros((nSitesS, nSitesS), complex)
    for (i, ijk) in enumerate(sc.iTs.T):
        CoreH_R[nSitesU * i:nSitesU *
                (i + 1), :] = sc._ConstructTranslatedRows(CoreH_SymUq, ijk)
    print "CoreH orig:\n%s" % CoreH
    print "CoreH reconstructed:\n%s" % CoreH_R
    print "difference norm to orig: %.2e" % la.norm(CoreH_R - CoreH)
Beispiel #17
0
 def GetRdm(self):
     #return 2.0 * dot(self.Orbs[:,:nOcc], self.Orbs[:,:nOcc].T)
     return mdot(self.Orbs, diag(self.OccNumbers), self.Orbs.T)