def _calc_lr(self, x, tmp, calc_l=False, A1=None, A2=None, rescale=True, max_itr=1000, rtol=1E-14, atol=1E-14): """Power iteration to obtain eigenvector corresponding to largest eigenvalue. x is modified in place. """ if A1 is None: A1 = self.A if A2 is None: A2 = self.A try: norm = la.get_blas_funcs("nrm2", [x]) except (ValueError, AttributeError): norm = np.linalg.norm # try: # allclose = ac.allclose_mat # except: # allclose = np.allclose # print "Falling back to numpy allclose()!" n = x.size #we will scale x so that stuff doesn't get too small x *= n / norm(x.ravel()) tmp[:] = x for i in xrange(max_itr): x[:] = tmp if calc_l: tm.eps_l_noop_inplace(x, A1, A2, tmp) else: tm.eps_r_noop_inplace(x, A1, A2, tmp) ev_mag = norm(tmp.ravel()) / n ev = (tmp.mean() / x.mean()).real tmp *= (1 / ev_mag) if norm((tmp - x).ravel()) < atol + rtol * n: # if allclose(tmp, x, rtol, atol): #print (i, ev, ev_mag, norm((tmp - x).ravel())/n, atol, rtol) x[:] = tmp break # else: # print (i, ev, ev_mag, norm((tmp - x).ravel())/norm(x.ravel()), atol, rtol) if rescale and not abs(ev - 1) < atol: A1 *= 1 / sp.sqrt(ev) if self.sanity_checks: if not A1 is A2: log.warning("Sanity check failed: Re-scaling with A1 <> A2!") if calc_l: tm.eps_l_noop_inplace(x, A1, A2, tmp) else: tm.eps_r_noop_inplace(x, A1, A2, tmp) ev = tmp.mean() / x.mean() if not abs(ev - 1) < atol: log.warning("Sanity check failed: Largest ev after re-scale = %s", ev) return x, i < max_itr - 1, i
def calc_BHB_prereq(self, tdvp, tdvp2): """Calculates prerequisites for the application of the effective Hamiltonian in terms of tangent vectors. This is called (indirectly) by the self.excite.. functions. Parameters ---------- tdvp2: EvoMPS_TDVP_Uniform Second state (may be the same, or another ground state). Returns ------- A lot of stuff. """ l = tdvp.l[0] r_ = tdvp2.r[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] A = tdvp.A[0] A_ = tdvp2.A[0] #Note: V has ~ D**2 * q**2 elements. We avoid making any copies of it except this one. # This one is only needed because low-level routines force V_[s] to be contiguous. # TODO: Store V instead of Vsh in tdvp_uniform too... V_ = sp.transpose(tdvp2.Vsh[0], axes=(0, 2, 1)).conj().copy(order='C') if self.ham_sites == 2: #eyeham = m.eyemat(self.q, dtype=sp.complex128) eyeham = sp.eye(self.q, dtype=sp.complex128) #diham = m.simple_diag_matrix(sp.repeat([-tdvp.h_expect.real], self.q)) diham = -tdvp.h_expect.real * sp.eye(self.q, dtype=sp.complex128) _ham_tp = self.ham_tp + [[diham, eyeham]] #subtract norm dof Ao1 = get_Aop(A, _ham_tp, 2, conj=False) AhlAo1 = [tm.eps_l_op_1s(l, A, A, o1.conj().T) for o1, o2 in _ham_tp] A_o2c = get_Aop(A_, _ham_tp, 1, conj=True) Ao1c = get_Aop(A, _ham_tp, 0, conj=True) A_Vr_ho2 = [tm.eps_r_op_1s(r__sqrt, A_, V_, o2) for o1, o2 in _ham_tp] A_A_o12c = get_A_ops(A_, A_, _ham_tp, conj=True) A_o1 = get_Aop(A_, _ham_tp, 2, conj=False) tmp = sp.empty((A_.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') rhs10 = 0 for al in xrange(len(A_o1)): tmp2 = tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2) tmp3 = m.mmul(tmp2, r__sqrt_i) rhs10 += tm.eps_r_noop_inplace(tmp3, A_o1[al], V_, tmp) return V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp elif self.ham_sites == 3: return
def restore_LCF(self): Gm1 = sp.eye(self.D[0], dtype=self.typ) #This is actually just the number 1 for n in xrange(1, self.N): self.l[n], G, Gi = tm.restore_LCF_l(self.A[n], self.l[n - 1], Gm1, zero_tol=self.zero_tol, sanity_checks=self.sanity_checks) Gm1 = G #Now do A[N]... #Apply the remaining G[N - 1] from the previous step. for s in xrange(self.q[self.N]): self.A[self.N][s] = Gm1.dot(self.A[self.N][s]) #Now finish off tm.eps_l_noop_inplace(self.l[self.N - 1], self.A[self.N], self.A[self.N], out=self.l[self.N]) #normalize GNi = 1. / sp.sqrt(self.l[self.N].squeeze().real) self.A[self.N] *= GNi self.l[self.N][:] = 1 if self.sanity_checks: lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N], self.A[self.N]) if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF!: l_N is bad / norm failure") #diag r Gi = sp.eye(self.D[self.N], dtype=self.typ) for n in xrange(self.N, 1, -1): self.r[n - 1], Gm1, Gm1_i = tm.restore_LCF_r(self.A[n], self.r[n], Gi, self.sanity_checks) Gi = Gm1_i #Apply remaining G1i to A[1] for s in xrange(self.q[1]): self.A[1][s] = self.A[1][s].dot(Gi) #Deal with final, scalar r[0] tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0]) if self.sanity_checks: if not sp.allclose(self.r[0], 1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF!: r_0 is bad / norm failure") log.warning("r_0 = %s", self.r[0].squeeze().real) for n in xrange(1, self.N + 1): l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n]) if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11): log.warning("Sanity Fail in restore_LCF!: l_%u is bad (off by %g)", n, la.norm(l - self.l[n])) log.warning((l - self.l[n]).diagonal().real)
def matvec(self, v): x = v.reshape((self.D, self.D)) if self.left: #Multiplying from the left, but x is a col. vector, so use mat_dagger Ehx = tm.eps_l_noop_inplace(x, self.A1, self.A2, self.out) if self.pseudo: QEQhx = Ehx - self.l * m.adot(self.r, x) res = x - sp.exp(-1.j * self.p) * QEQhx else: res = x - sp.exp(-1.j * self.p) * Ehx else: Ex = tm.eps_r_noop_inplace(x, self.A1, self.A2, self.out) if self.pseudo: QEQx = Ex - self.r * m.adot(self.l, x) res = x - sp.exp(1.j * self.p) * QEQx else: res = x - sp.exp(1.j * self.p) * Ex return res.ravel()
def matvec(self, v): x = v.reshape((self.D, self.D)) res = self.tmp out = self.out res[:] = x if self.left: # Multiplying from the left, but x is a col. vector, so use mat_dagger for k in xrange(len(self.A1)): out = tm.eps_l_noop_inplace(res, self.A1[k], self.A2[k], out) tmp = res res = out out = tmp if self.pseudo: out[:] = self.lL out *= m.adot(self.rL, x) res -= out res *= -sp.exp(-1.0j * self.p) res += x else: res *= -sp.exp(-1.0j * self.p) res += x else: for k in xrange(len(self.A1) - 1, -1, -1): out = tm.eps_r_noop_inplace(res, self.A1[k], self.A2[k], out) tmp = res res = out out = tmp if self.pseudo: out[:] = self.rL out *= m.adot(self.lL, x) res -= out res *= -sp.exp(1.0j * self.p) res += x else: res *= -sp.exp(1.0j * self.p) res += x return ( res.copy().ravel() ) # apparently we can't reuse the memory we return (seems to blow up lgmres), so we make a copy
def matvec(self, v): x = v.reshape((self.D, self.D)) res = self.tmp out = self.out res[:] = x if self.left: #Multiplying from the left, but x is a col. vector, so use mat_dagger for k in xrange(len(self.A1)): out = tm.eps_l_noop_inplace(res, self.A1[k], self.A2[k], out) tmp = res res = out out = tmp if self.pseudo: out[:] = self.lL out *= m.adot(self.rL, x) res -= out res *= -sp.exp(-1.j * self.p) res += x else: res *= -sp.exp(-1.j * self.p) res += x else: for k in xrange(len(self.A1) - 1, -1, -1): out = tm.eps_r_noop_inplace(res, self.A1[k], self.A2[k], out) tmp = res res = out out = tmp if self.pseudo: out[:] = self.rL out *= m.adot(self.lL, x) res -= out res *= -sp.exp(1.j * self.p) res += x else: res *= -sp.exp(1.j * self.p) res += x return res.copy().ravel() #apparently we can't reuse the memory we return (seems to blow up lgmres), so we make a copy
def restore_RCF(self, update_l=True, normalize=True, diag_l=True): """Use a gauge-transformation to restore right canonical form. Implements the conditions for right canonical form from sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This performs two 'almost' gauge transformations, where the 'almost' means we allow the norm to vary (if "normalize" = True). The last step (A[1]) is done diffently to the others since G[0], the gauge-transf. matrix, is just a number, which can be found more efficiently and accurately without using matrix methods. The last step (A[1]) is important because, if we have successfully made r[1] = 1 in the previous steps, it fully determines the normalization of the state via r[0] ( = l[N]). Optionally (normalize=False), the function will not attempt to make A[1] satisfy the orthonorm. condition, and will take G[0] = 1 = G[N], thus performing a pure gauge-transformation, but not ensuring complete canonical form. It is also possible to begin the process from a site n other than N, in case the sites > n are known to be in the desired form already. It is also possible to skip the diagonalization of the l's, such that only the right orthonormalization condition (r_n = eye) is met. By default, the l's are updated even if diag_l=False. Parameters ---------- update_l : bool Whether to call calc_l() after completion (defaults to True) normalize : bool Whether to also attempt to normalize the state. diag_l : bool Whether to put l in diagonal form (defaults to True) """ start = self.N G_n_i = sp.eye(self.D[start], dtype=self.typ) #This is actually just the number 1 for n in xrange(start, 1, -1): self.r[n - 1], G_n, G_n_i = tm.restore_RCF_r(self.A[n], self.r[n], G_n_i, sc_data=('site', n), zero_tol=self.zero_tol, sanity_checks=self.sanity_checks) #Now do A[1]... #Apply the remaining G[1]^-1 from the previous step. for s in xrange(self.q[1]): self.A[1][s] = m.mmul(self.A[1][s], G_n_i) #Now finish off tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0]) if normalize: G0 = 1. / sp.sqrt(self.r[0].squeeze().real) self.A[1] *= G0 self.r[0][:] = 1 if self.sanity_checks: r0 = tm.eps_r_noop(self.r[1], self.A[1], self.A[1]) if not sp.allclose(r0, 1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF!: r_0 is bad / norm failure") if diag_l: G_nm1 = sp.eye(self.D[0], dtype=self.typ) for n in xrange(1, self.N): self.l[n], G_nm1, G_nm1_i = tm.restore_RCF_l(self.A[n], self.l[n - 1], G_nm1, self.sanity_checks) #Apply remaining G_Nm1 to A[N] n = self.N for s in xrange(self.q[n]): self.A[n][s] = m.mmul(G_nm1, self.A[n][s]) #Deal with final, scalar l[N] tm.eps_l_noop_inplace(self.l[n - 1], self.A[n], self.A[n], out=self.l[n]) if self.sanity_checks: if not sp.allclose(self.l[self.N].real, 1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF!: l_N is bad / norm failure") log.warning("l_N = %s", self.l[self.N].squeeze().real) for n in xrange(1, self.N + 1): r_nm1 = tm.eps_r_noop(self.r[n], self.A[n], self.A[n]) #r_nm1 = tm.eps_r_noop(m.eyemat(self.D[n], self.typ), self.A[n], self.A[n]) if not sp.allclose(r_nm1, self.r[n - 1], atol=1E-11, rtol=1E-11): log.warning("Sanity Fail in restore_RCF!: r_%u is bad (off by %g)", n, la.norm(r_nm1 - self.r[n - 1])) elif update_l: self.calc_l()
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: return else: V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp = prereq A = tdvp.A[0] A_ = tdvp2.A[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(m.mmul(V_[s], r__sqrt_i))) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') res_ls = 0 res_lsi = 0 exp = sp.exp if self.ham_sites == 3: pass else: Bo1 = get_Aop(B, _ham_tp, 2, conj=False) tmp = sp.empty((B.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') tmp3 = sp.empty_like(tmp2, order='C') for al in xrange(len(Bo1)): tmp3 = m.dot_inplace(tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2), r__sqrt_i, tmp3) res_ls += tm.eps_r_noop_inplace(tmp3, Bo1[al], V_, tmp) #1 tmp3 = m.dot_inplace(tm.eps_r_noop_inplace(r_, B, A_o2c[al], tmp2), r__sqrt_i, tmp3) tmp = tm.eps_r_noop_inplace(tmp3, Ao1[al], V_, tmp) #3 tmp *= exp(+1.j * p) res_ls += tmp del(tmp) del(tmp2) del(tmp3) res_lsi += sp.exp(-1.j * p) * Mh.dot(rhs10) #10 if self.ham_sites == 3: pass else: Bo2 = get_Aop(B, _ham_tp, 3, conj=False) for al in xrange(len(AhlAo1)): res_lsi += AhlAo1[al].dot(tm.eps_r_noop(r__sqrt, Bo2[al], V_)) #2 res_lsi += exp(-1.j * p) * tm.eps_l_noop(l, Ao1c[al], B).dot(A_Vr_ho2[al]) #4 res_lsi += exp(-2.j * p) * tm.eps_l_noop(Mh, Ao1c[al], A_).dot(A_Vr_ho2[al]) #12 K__rri = m.mmul(K__r, r__sqrt_i) res_ls += tm.eps_r_noop(K__rri, B, V_) #5 res_lsi += K_l.dot(tm.eps_r_noop(r__sqrt, B, V_)) #6 res_lsi += sp.exp(-1.j * p) * Mh.dot(tm.eps_r_noop(K__rri, A_, V_)) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: pass elif self.ham_sites == 2: tmp = 0 for al in xrange(len(A_A_o12c)): tmp += sp.exp(+1.j * p) * tm.eps_r_noop(tm.eps_r_noop(r_, A_, A_A_o12c[al][1]), B, A_A_o12c[al][0]) #9 tmp += sp.exp(+2.j * p) * tm.eps_r_noop(tm.eps_r_noop(r_, B, A_A_o12c[al][1]), A, A_A_o12c[al][0]) #11 y = y1 + tmp #7, 9, 11 del(tmp) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res_ls += tm.eps_r_noop(m.mmul(y_pi, r__sqrt_i), A, V_) res = l_sqrt.dot(res_ls) res += l_sqrt_i.dot(res_lsi) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
def restore_LCF(self): Gm1 = sp.eye(self.D[0], dtype=self.typ) #This is actually just the number 1 for n in xrange(1, self.N): self.l[n], G, Gi = tm.restore_LCF_l( self.A[n], self.l[n - 1], Gm1, zero_tol=self.zero_tol, sanity_checks=self.sanity_checks) Gm1 = G #Now do A[N]... #Apply the remaining G[N - 1] from the previous step. for s in xrange(self.q[self.N]): self.A[self.N][s] = Gm1.dot(self.A[self.N][s]) #Now finish off tm.eps_l_noop_inplace(self.l[self.N - 1], self.A[self.N], self.A[self.N], out=self.l[self.N]) #normalize GNi = 1. / sp.sqrt(self.l[self.N].squeeze().real) self.A[self.N] *= GNi self.l[self.N][:] = 1 if self.sanity_checks: lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N], self.A[self.N]) if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12): log.warning( "Sanity Fail in restore_LCF!: l_N is bad / norm failure") #diag r Gi = sp.eye(self.D[self.N], dtype=self.typ) for n in xrange(self.N, 1, -1): self.r[n - 1], Gm1, Gm1_i = tm.restore_LCF_r( self.A[n], self.r[n], Gi, self.sanity_checks) Gi = Gm1_i #Apply remaining G1i to A[1] for s in xrange(self.q[1]): self.A[1][s] = self.A[1][s].dot(Gi) #Deal with final, scalar r[0] tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0]) if self.sanity_checks: if not sp.allclose(self.r[0], 1, atol=1E-12, rtol=1E-12): log.warning( "Sanity Fail in restore_LCF!: r_0 is bad / norm failure") log.warning("r_0 = %s", self.r[0].squeeze().real) for n in xrange(1, self.N + 1): l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n]) if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11): log.warning( "Sanity Fail in restore_LCF!: l_%u is bad (off by %g)", n, la.norm(l - self.l[n])) log.warning((l - self.l[n]).diagonal().real)
def restore_RCF(self, update_l=True, normalize=True, diag_l=True): """Use a gauge-transformation to restore right canonical form. Implements the conditions for right canonical form from sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This performs two 'almost' gauge transformations, where the 'almost' means we allow the norm to vary (if "normalize" = True). The last step (A[1]) is done diffently to the others since G[0], the gauge-transf. matrix, is just a number, which can be found more efficiently and accurately without using matrix methods. The last step (A[1]) is important because, if we have successfully made r[1] = 1 in the previous steps, it fully determines the normalization of the state via r[0] ( = l[N]). Optionally (normalize=False), the function will not attempt to make A[1] satisfy the orthonorm. condition, and will take G[0] = 1 = G[N], thus performing a pure gauge-transformation, but not ensuring complete canonical form. It is also possible to begin the process from a site n other than N, in case the sites > n are known to be in the desired form already. It is also possible to skip the diagonalization of the l's, such that only the right orthonormalization condition (r_n = eye) is met. By default, the l's are updated even if diag_l=False. Parameters ---------- update_l : bool Whether to call calc_l() after completion (defaults to True) normalize : bool Whether to also attempt to normalize the state. diag_l : bool Whether to put l in diagonal form (defaults to True) """ start = self.N G_n_i = sp.eye(self.D[start], dtype=self.typ) #This is actually just the number 1 for n in xrange(start, 1, -1): self.r[n - 1], G_n, G_n_i = tm.restore_RCF_r( self.A[n], self.r[n], G_n_i, sc_data=('site', n), zero_tol=self.zero_tol, sanity_checks=self.sanity_checks) #Now do A[1]... #Apply the remaining G[1]^-1 from the previous step. for s in xrange(self.q[1]): self.A[1][s] = m.mmul(self.A[1][s], G_n_i) #Now finish off tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0]) if normalize: G0 = 1. / sp.sqrt(self.r[0].squeeze().real) self.A[1] *= G0 self.r[0][:] = 1 if self.sanity_checks: r0 = tm.eps_r_noop(self.r[1], self.A[1], self.A[1]) if not sp.allclose(r0, 1, atol=1E-12, rtol=1E-12): log.warning( "Sanity Fail in restore_RCF!: r_0 is bad / norm failure" ) if diag_l: G_nm1 = sp.eye(self.D[0], dtype=self.typ) for n in xrange(1, self.N): self.l[n], G_nm1, G_nm1_i = tm.restore_RCF_l( self.A[n], self.l[n - 1], G_nm1, self.sanity_checks) #Apply remaining G_Nm1 to A[N] n = self.N for s in xrange(self.q[n]): self.A[n][s] = m.mmul(G_nm1, self.A[n][s]) #Deal with final, scalar l[N] tm.eps_l_noop_inplace(self.l[n - 1], self.A[n], self.A[n], out=self.l[n]) if self.sanity_checks: if not sp.allclose( self.l[self.N].real, 1, atol=1E-12, rtol=1E-12): log.warning( "Sanity Fail in restore_RCF!: l_N is bad / norm failure" ) log.warning("l_N = %s", self.l[self.N].squeeze().real) for n in xrange(1, self.N + 1): r_nm1 = tm.eps_r_noop(self.r[n], self.A[n], self.A[n]) #r_nm1 = tm.eps_r_noop(m.eyemat(self.D[n], self.typ), self.A[n], self.A[n]) if not sp.allclose( r_nm1, self.r[n - 1], atol=1E-11, rtol=1E-11): log.warning( "Sanity Fail in restore_RCF!: r_%u is bad (off by %g)", n, la.norm(r_nm1 - self.r[n - 1])) elif update_l: self.calc_l()
def _calc_lr_ARPACK(self, x, tmp, calc_l=False, A1=None, A2=None, rescale=True, tol=1E-14, ncv=None, k=1): if A1 is None: A1 = self.A if A2 is None: A2 = self.A if self.D == 1: x.fill(1) if calc_l: ev = tm.eps_l_noop(x, A1, A2)[0, 0] else: ev = tm.eps_r_noop(x, A1, A2)[0, 0] if rescale and not abs(ev - 1) < tol: A1 *= 1 / sp.sqrt(ev) return x, True, 1 try: norm = la.get_blas_funcs("nrm2", [x]) except (ValueError, AttributeError): norm = np.linalg.norm n = x.size #we will scale x so that stuff doesn't get too small #start = time.clock() opE = EOp(A1, A2, calc_l) x *= n / norm(x.ravel()) try: ev, eV = las.eigs(opE, which='LM', k=k, v0=x.ravel(), tol=tol, ncv=ncv) conv = True except las.ArpackNoConvergence: log.warning("Reset! (l? %s)", calc_l) ev, eV = las.eigs(opE, which='LM', k=k, tol=tol, ncv=ncv) conv = True #print ev2 #print ev2 * ev2.conj() ind = ev.argmax() ev = np.real_if_close(ev[ind]) ev = np.asscalar(ev) eV = eV[:, ind] #remove any additional phase factor eVmean = eV.mean() eV *= sp.sqrt(sp.conj(eVmean) / eVmean) if eV.mean() < 0: eV *= -1 eV = eV.reshape(self.D, self.D) eV *= n / norm(eV.ravel()) x[:] = eV #print "splinalg: %g" % (time.clock() - start) #print "Herm? %g" % norm((eV - m.H(eV)).ravel()) #print "Norm of diff: %g" % norm((eV - x).ravel()) #print "Norms: (%g, %g)" % (norm(eV.ravel()), norm(x.ravel())) if rescale and not abs(ev - 1) < tol: A1 *= 1 / sp.sqrt(ev) if self.sanity_checks: if not A1 is A2: log.warning("Sanity check failed: Re-scaling with A1 <> A2!") if calc_l: tm.eps_l_noop_inplace(x, A1, A2, tmp) else: tm.eps_r_noop_inplace(x, A1, A2, tmp) ev = tmp.mean() / x.mean() if not abs(ev - 1) < tol: log.warning("Sanity check failed: Largest ev after re-scale = %s", ev) return x, conv, opE.calls
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: return else: V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp = prereq A = tdvp.A[0] A_ = tdvp2.A[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(m.mmul(V_[s], r__sqrt_i))) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') res_ls = 0 res_lsi = 0 exp = sp.exp if self.ham_sites == 3: pass else: Bo1 = get_Aop(B, _ham_tp, 2, conj=False) tmp = sp.empty((B.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') tmp3 = sp.empty_like(tmp2, order='C') for al in xrange(len(Bo1)): tmp3 = m.dot_inplace( tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2), r__sqrt_i, tmp3) res_ls += tm.eps_r_noop_inplace(tmp3, Bo1[al], V_, tmp) #1 tmp3 = m.dot_inplace( tm.eps_r_noop_inplace(r_, B, A_o2c[al], tmp2), r__sqrt_i, tmp3) tmp = tm.eps_r_noop_inplace(tmp3, Ao1[al], V_, tmp) #3 tmp *= exp(+1.j * p) res_ls += tmp del (tmp) del (tmp2) del (tmp3) res_lsi += sp.exp(-1.j * p) * Mh.dot(rhs10) #10 if self.ham_sites == 3: pass else: Bo2 = get_Aop(B, _ham_tp, 3, conj=False) for al in xrange(len(AhlAo1)): res_lsi += AhlAo1[al].dot(tm.eps_r_noop(r__sqrt, Bo2[al], V_)) #2 res_lsi += exp(-1.j * p) * tm.eps_l_noop(l, Ao1c[al], B).dot( A_Vr_ho2[al]) #4 res_lsi += exp(-2.j * p) * tm.eps_l_noop(Mh, Ao1c[al], A_).dot( A_Vr_ho2[al]) #12 K__rri = m.mmul(K__r, r__sqrt_i) res_ls += tm.eps_r_noop(K__rri, B, V_) #5 res_lsi += K_l.dot(tm.eps_r_noop(r__sqrt, B, V_)) #6 res_lsi += sp.exp(-1.j * p) * Mh.dot(tm.eps_r_noop(K__rri, A_, V_)) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: pass elif self.ham_sites == 2: tmp = 0 for al in xrange(len(A_A_o12c)): tmp += sp.exp(+1.j * p) * tm.eps_r_noop( tm.eps_r_noop(r_, A_, A_A_o12c[al][1]), B, A_A_o12c[al][0]) #9 tmp += sp.exp(+2.j * p) * tm.eps_r_noop( tm.eps_r_noop(r_, B, A_A_o12c[al][1]), A, A_A_o12c[al][0]) #11 y = y1 + tmp #7, 9, 11 del (tmp) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res_ls += tm.eps_r_noop(m.mmul(y_pi, r__sqrt_i), A, V_) res = l_sqrt.dot(res_ls) res += l_sqrt_i.dot(res_lsi) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning( "Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
def calc_BHB_prereq(self, tdvp, tdvp2): """Calculates prerequisites for the application of the effective Hamiltonian in terms of tangent vectors. This is called (indirectly) by the self.excite.. functions. Parameters ---------- tdvp2: EvoMPS_TDVP_Uniform Second state (may be the same, or another ground state). Returns ------- A lot of stuff. """ l = tdvp.l[0] r_ = tdvp2.r[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] A = tdvp.A[0] A_ = tdvp2.A[0] #Note: V has ~ D**2 * q**2 elements. We avoid making any copies of it except this one. # This one is only needed because low-level routines force V_[s] to be contiguous. # TODO: Store V instead of Vsh in tdvp_uniform too... V_ = sp.transpose(tdvp2.Vsh[0], axes=(0, 2, 1)).conj().copy(order='C') if self.ham_sites == 2: #eyeham = m.eyemat(self.q, dtype=sp.complex128) eyeham = sp.eye(self.q, dtype=sp.complex128) #diham = m.simple_diag_matrix(sp.repeat([-tdvp.h_expect.real], self.q)) diham = -tdvp.h_expect.real * sp.eye(self.q, dtype=sp.complex128) _ham_tp = self.ham_tp + [[diham, eyeham]] #subtract norm dof Ao1 = get_Aop(A, _ham_tp, 2, conj=False) AhlAo1 = [ tm.eps_l_op_1s(l, A, A, o1.conj().T) for o1, o2 in _ham_tp ] A_o2c = get_Aop(A_, _ham_tp, 1, conj=True) Ao1c = get_Aop(A, _ham_tp, 0, conj=True) A_Vr_ho2 = [ tm.eps_r_op_1s(r__sqrt, A_, V_, o2) for o1, o2 in _ham_tp ] A_A_o12c = get_A_ops(A_, A_, _ham_tp, conj=True) A_o1 = get_Aop(A_, _ham_tp, 2, conj=False) tmp = sp.empty((A_.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') rhs10 = 0 for al in xrange(len(A_o1)): tmp2 = tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2) tmp3 = m.mmul(tmp2, r__sqrt_i) rhs10 += tm.eps_r_noop_inplace(tmp3, A_o1[al], V_, tmp) return V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp elif self.ham_sites == 3: return