Exemplo n.º 1
0
    def calc_l_r_roots(self, n):
        """Returns the matrix square roots (and inverses) needed to calculate B.

        Hermiticity of l[n] and r[n] is used to speed this up.
        If an exception occurs here, it is probably because these matrices
        are no longer Hermitian (enough).
        
        If l[n] or r[n] are diagonal or the identity, further optimizations are
        used.
        """
        assert 0 < n <= self.N, 'calc_l_r_roots: Bad n!'
        
        l_sqrt, l_sqrt_i, r_sqrt, r_sqrt_i = tm.calc_l_r_roots(self.l[n - 1], 
                                                               self.r[n], 
                                                               zero_tol=self.zero_tol,
                                                               sanity_checks=self.sanity_checks)

        return l_sqrt, r_sqrt, l_sqrt_i, r_sqrt_i
Exemplo n.º 2
0
    def calc_l_r_roots(self, n):
        """Returns the matrix square roots (and inverses) needed to calculate B.

        Hermiticity of l[n] and r[n] is used to speed this up.
        If an exception occurs here, it is probably because these matrices
        are no longer Hermitian (enough).
        
        If l[n] or r[n] are diagonal or the identity, further optimizations are
        used.
        """
        assert 0 < n <= self.N, 'calc_l_r_roots: Bad n!'

        l_sqrt, l_sqrt_i, r_sqrt, r_sqrt_i = tm.calc_l_r_roots(
            self.l[n - 1],
            self.r[n],
            zero_tol=self.zero_tol,
            sanity_checks=self.sanity_checks)

        return l_sqrt, r_sqrt, l_sqrt_i, r_sqrt_i
Exemplo n.º 3
0
 def _calc_B_l(self, n, set_eta=True):
     if self.q[n] * self.D[n - 1] - self.D[n] > 0:
         l_sqrt, l_sqrt_inv, r_sqrt, r_sqrt_inv = tm.calc_l_r_roots(self.l[n - 1], 
                                                                self.r[n], 
                                                                zero_tol=self.zero_tol,
                                                                sanity_checks=self.sanity_checks,
                                                                sc_data=('site', n))
         
         Vsh = tm.calc_Vsh_l(self.A[n], l_sqrt, sanity_checks=self.sanity_checks)
         
         x = self.calc_x_l(n, Vsh, l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv)
         
         if set_eta:
             self.eta[n] = sp.sqrt(m.adot(x, x))
 
         B = sp.empty_like(self.A[n])
         for s in xrange(self.q[n]):
             B[s] = m.mmul(l_sqrt_inv, m.H(Vsh[s]), x, r_sqrt_inv)
         return B
     else:
         return None
Exemplo n.º 4
0
 def _calc_B_l_n(self, n, set_eta=True, l_s_m1=None, l_si_m1=None, r_s=None, r_si=None, Vlh=None):
     if self.q[n] * self.D[n - 1] - self.D[n] > 0:
         if l_s_m1 is None:
             l_s_m1, l_si_m1, r_s, r_si = tm.calc_l_r_roots(self.l[n - 1], self.r[n], 
                                                        zero_tol=self.zero_tol,
                                                        sanity_checks=self.sanity_checks,
                                                        sc_data=('site', n))
         
         if Vlh is None:
             Vlh = tm.calc_Vsh_l(self.A[n], l_s_m1, sanity_checks=self.sanity_checks)
         
         x = self.calc_x_l(n, Vlh, l_s_m1, r_s, l_si_m1, r_si)
         
         if set_eta:
             self.eta_sq[n] = m.adot(x, x)
 
         B = sp.empty_like(self.A[n])
         for s in xrange(self.q[n]):
             B[s] = m.mmul(l_si_m1, m.H(Vlh[s]), x, r_si)
         return B
     else:
         return None
Exemplo n.º 5
0
 def take_step(self, dtau, B=None, save_memory=False, calc_Y_2s=False, 
               dynexp=False, dD_max=16, D_max=0, sv_tol=1E-14):   
     """Performs a complete forward-Euler step of imaginary time dtau.
     
     The operation is A[n] -= dtau * B[n] with B[n] from self.calc_B(n).
     
     If dtau is itself imaginary, real-time evolution results.
     
     Second-order corrections to the dynamics can be calculated if desired.
     If they are, the norm of the second-order contributions is stored in 
     self.eta_BB. For nearest-neighbour Hamiltonians, 
     this captures all errors made by projecting onto the MPS tangent plane.
             
     The second-order contributions also form the basis of the dynamical 
     expansion scheme (dynexp), which captures a configurable (dD_max)
     amount of these contributions by increasing the bond dimension.
     
     Parameters
     ----------
     dtau : complex
         The (imaginary or real) amount of imaginary time (tau) to step.
     B : sequence of ndarray
         The direction to step in. Not compatible with dynexp or save_memory.
     save_memory : bool
         Whether to save memory by avoiding storing all B[n] at once.
     calc_Y_2s : bool
         Whether to calculate the second-order contributions to the dynamics.
     dynexp : bool
         Whether to increase the bond dimension to capture more of the dynamics.
     dD_max : int
         The maximum amount by which to increase the bond dimension (for any site).
     D_max : int
         The maximum bond dimension to allow when expanding.
     sv_tol : float
         Only use singular values larger than this for dynamical expansion.
     """
     self.eta_sq.fill(0)    
     self.etaBB_sq.fill(0)
     
     if (self.gauge_fixing == 'right' and save_memory and not calc_Y_2s and not dynexp
         and B is None):
         B = [None] * (self.N + 1)
         for n in xrange(1, self.N + self.ham_sites):
             #V is not always defined (e.g. at the right boundary vector, and possibly before)
             if n <= self.N:
                 B[n] = self.calc_B(n)
             
             #Only change an A after the next B no longer depends on it!
             if n >= self.ham_sites:
                 m = n - self.ham_sites + 1
                 if not B[m] is None:
                     self.A[m] += -dtau * B[m]
                     B[m] = None
          
         assert all(x is None for x in B), "take_step update incomplete!"
     else:
         if B is None or dynexp or calc_Y_2s:
             l_s = sp.empty((self.N + 1), dtype=sp.ndarray)
             l_si = sp.empty((self.N + 1), dtype=sp.ndarray)
             r_s = sp.empty((self.N + 1), dtype=sp.ndarray)
             r_si = sp.empty((self.N + 1), dtype=sp.ndarray)
             Vrh = sp.empty((self.N + 1), dtype=sp.ndarray)
             Vlh = sp.empty((self.N + 1), dtype=sp.ndarray)
             for n in xrange(1, self.N + 1):
                 l_s[n-1], l_si[n-1], r_s[n], r_si[n] = tm.calc_l_r_roots(self.l[n - 1], self.r[n], 
                                                                zero_tol=self.zero_tol,
                                                                sanity_checks=self.sanity_checks,
                                                                sc_data=('site', n))
             
             if dynexp or calc_Y_2s or self.gauge_fixing == 'left':
                 for n in xrange(1, self.N + 1):
                     Vlh[n] = tm.calc_Vsh_l(self.A[n], l_s[n-1], sanity_checks=self.sanity_checks)
             if dynexp or calc_Y_2s or self.gauge_fixing == 'right':
                 for n in xrange(1, self.N + 1):
                     Vrh[n] = tm.calc_Vsh(self.A[n], r_s[n], sanity_checks=self.sanity_checks)
 
             if B is None:
                 B = self.calc_B(set_eta=True, l_s=l_s, l_si=l_si, 
                                 r_s=r_s, r_si=r_si, Vlh=Vlh, Vrh=Vrh)
         
         if calc_Y_2s or dynexp:
             Y, self.etaBB_sq = self.calc_BB_Y_2s(l_s, l_si, r_s, r_si, Vrh, Vlh)
             
         if dynexp:
             BB12, BB21, dD = self.calc_BB_2s(Y, Vlh, Vrh, l_si, r_si, 
                                              dD_max=dD_max, sv_tol=sv_tol,
                                              D_max=D_max)
                                              
             for n in xrange(1, self.N + 1):
                 if not B[n] is None:
                     self.A[n] += -dtau * B[n]
                     
             if sp.any(dD > 0):
                 oldA = self.A
                 oldD = self.D.copy()
                 oldeta = self.eta_sq
                 oldetaBB = self.etaBB_sq
                 
                 self.D += dD
                 self._init_arrays()
     
                 for n in xrange(1, self.N + 1):
                     self.A[n][:, :oldD[n - 1], :oldD[n]] = oldA[n]
                     
                     if not BB12[n] is None:
                         self.A[n][:, :oldD[n - 1], oldD[n]:] = -1.j * sp.sqrt(dtau) * BB12[n]
                     if not BB21[n] is None:
                         self.A[n][:, oldD[n - 1]:, :oldD[n]] = -1.j * sp.sqrt(dtau) * BB21[n]
                     
                 log.info("Dyn. expanded! New D: %s", self.D)
                 self.eta_sq = oldeta
                 self.etaBB_sq = oldetaBB
         else:
             for n in xrange(1, self.N + 1):
                 if not B[n] is None:
                     self.A[n] += -dtau * B[n]
                    
     self.eta = sp.sqrt(self.eta_sq.sum())
     self.etaBB = sp.sqrt(self.etaBB_sq.sum())