def expect_3s(self, op, n): """Computes the expectation value of a nearest-neighbour three-site operator. The operator should be a q[n] x q[n + 1] x q[n + 2] x q[n] x q[n + 1] x q[n + 2] array such that op[s, t, u, v, w, x] = <stu|op|vwx> or a function of the form op(s, t, u, v, w, x) = <stu|op|vwx>. The state must be up-to-date -- see self.update()! Parameters ---------- op : ndarray or callable The operator array or function. n : int The leftmost site number (operator acts on n, n + 1, n + 2). Returns ------- expval : floating point number The expectation value (data type may be complex) """ A = self.A[n] Ap1 = self.A[n + 1] Ap2 = self.A[n + 2] AAA = tm.calc_AAA(A, Ap1, Ap2) if callable(op): op = sp.vectorize(op, otypes=[sp.complex128]) op = sp.fromfunction(op, (A.shape[0], Ap1.shape[0], Ap2.shape[0], A.shape[0], Ap1.shape[0], Ap2.shape[0])) C = tm.calc_C_3s_mat_op_AAA(op, AAA) res = tm.eps_r_op_3s_C123_AAA456(self.r[n + 2], C, AAA) return m.adot(self.l[n - 1], res)
def calc_C(self, n_low=-1, n_high=-1): """Generates the C tensors used to calculate the K's and ultimately the B's. This is called automatically by self.update(). C[n] contains a contraction of the Hamiltonian self.ham with the parameter tensors over the local basis indices. This is prerequisite for calculating the tangent vector parameters B, which optimally approximate the exact time evolution. These are to be used on one side of the super-operator when applying the nearest-neighbour Hamiltonian, similarly to C in eqn. (44) of arXiv:1103.0936v2 [cond-mat.str-el], for the non-norm-preserving case. Makes use only of the nearest-neighbour Hamiltonian, and of the A's. C[n] depends on A[n] through A[n + self.ham_sites - 1]. """ if self.ham is None: return 0 if n_low < 1: n_low = 1 if n_high < 1: n_high = self.N - self.ham_sites + 1 for n in xrange(n_low, n_high + 1): if callable(self.ham): ham_n = lambda *args: self.ham(n, *args) ham_n = sp.vectorize(ham_n, otypes=[sp.complex128]) ham_n = sp.fromfunction(ham_n, tuple(self.C[n].shape[:-2] * 2)) else: ham_n = self.ham[n] if self.ham_sites == 2: AA = tm.calc_AA(self.A[n], self.A[n + 1]) self.C[n] = tm.calc_C_mat_op_AA(ham_n, AA) else: AAA = tm.calc_AAA(self.A[n], self.A[n + 1], self.A[n + 2]) self.C[n] = tm.calc_C_3s_mat_op_AAA(ham_n, AAA)
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): """As for self.calc_BHB(), but for Hamiltonian terms acting on three sites. """ if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: V_, Vr_, Vri_, C_, C_Vri_AA_, C_AAA_r_Ah_Vrih, \ C_AhAhlAA, C_AA_r_Ah_Vrih_, C_AAA_Vrh_, C_A_r_Ah_Vrih, \ C_AhlAA, C_AhAhlA, C_AA_Vrh, rhs10 = prereq else: C_, C_conj, V_, Vr_, Vri_, C_Vri_A_conj, C_AhlA, C_A_Vrh_, rhs10 = 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!") if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(Vri_[s])) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") if self.ham_sites == 3: BAA_ = tm.calc_AAA(B, A_, A_) ABA_ = tm.calc_AAA(A, B, A_) AAB = tm.calc_AAA(A, A, B) elif self.ham_sites == 2: BA_ = tm.calc_AA(B, A_) AB = tm.calc_AA(A, B) 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.sanity_tol, solver=pinv_solver, 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.H(M) if self.ham_sites == 3: res = l_sqrt.dot( tm.eps_r_op_3s_C123_AAA456(r_, BAA_, C_Vri_AA_) #1 1D + sp.exp(+1.j * p) * tm.eps_r_op_3s_C123_AAA456(r_, ABA_, C_Vri_AA_) #3 + sp.exp(+2.j * p) * tm.eps_r_op_3s_C123_AAA456(r_, AAB, C_Vri_AA_) #3c ) else: res = l_sqrt.dot( tm.eps_r_op_2s_AA12_C34(r_, BA_, C_Vri_A_conj) #1 OK + sp.exp(+1.j * p) * tm.eps_r_op_2s_AA12_C34(r_, AB, C_Vri_A_conj) #3 OK with 4 ) res += sp.exp(-1.j * p) * l_sqrt_i.dot(Mh.dot(rhs10)) #10 exp = sp.exp subres = sp.zeros_like(res) eye = m.eyemat(C_.shape[2], dtype=tdvp.typ) if self.ham_sites == 3: for s in xrange(self.q): subres += exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_AAA_r_Ah_Vrih[s])) #12 for t in xrange(self.q): subres += (C_AhAhlAA[t, s].dot(B[s]).dot(Vr_[t].conj().T)) #2b subres += (exp(-1.j * p) * A[s].conj().T.dot(l.dot(B[t])).dot(C_AA_r_Ah_Vrih_[s, t])) #4 subres += (exp(-3.j * p) * A[s].conj().T.dot(A[t].conj().T).dot(Mh).dot(C_AAA_Vrh_[t, s])) #12b for u in xrange(self.q): subres += (A[s].conj().T.dot(l.dot(A[t]).dot(B[u])).dot(C_A_r_Ah_Vrih[s, t, u])) #2 -ive of that it should be.... subres += (exp(+1.j * p) * C_AhlAA[u, t, s].dot(B[s]).dot(r_.dot(A_[t].conj().T)).dot(Vri_[u].conj().T)) #3b subres += (exp(-1.j * p) * C_AhAhlA[s, t, u].dot(B[t]).dot(A_[u]).dot(Vr_[s].conj().T)) #4b subres += (exp(-2.j * p) * A[s].conj().T.dot(A[t].conj().T).dot(l.dot(B[u])).dot(C_AA_Vrh[t, s, u])) #4c else: for s in xrange(self.q): #subres += C_AhlA[s, t].dot(B[s]).dot(Vr_[t].conj().T) #2 OK subres += tm.eps_r_noop(B[s], C_AhlA[:, s], Vr_) #+ exp(-1.j * p) * A[t].conj().T.dot(l.dot(B[s])).dot(C_A_Vrh_[s, t]) #4 OK with 3 subres += exp(-1.j * p) * tm.eps_l_noop(l.dot(B[s]), A, C_A_Vrh_[:, s]) #+ exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_[s, t])).dot(Vr_[t].conj().T)) #12 subres += exp(-2.j * p) * A[s].conj().T.dot(Mh).dot(tm.eps_r_noop(eye, C_[s], Vr_)) res += l_sqrt_i.dot(subres) res += l_sqrt.dot(tm.eps_r_noop(K__r, B, Vri_)) #5 res += l_sqrt_i.dot(K_l.dot(tm.eps_r_noop(r__sqrt, B, V_))) #6 res += sp.exp(-1.j * p) * l_sqrt_i.dot(Mh.dot(tm.eps_r_noop(K__r, A_, Vri_))) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: y2 = sp.exp(+1.j * p) * tm.eps_r_op_3s_C123_AAA456(r_, BAA_, C_) #9 y3 = sp.exp(+2.j * p) * tm.eps_r_op_3s_C123_AAA456(r_, ABA_, C_) #11 y4 = sp.exp(+3.j * p) * tm.eps_r_op_3s_C123_AAA456(r_, AAB, C_) #11b elif self.ham_sites == 2: y2 = sp.exp(+1.j * p) * tm.eps_r_op_2s_AA12_C34(r_, BA_, C_conj) #9 y3 = sp.exp(+2.j * p) * tm.eps_r_op_2s_AA12_C34(r_, AB, C_conj) #11 y4 = 0 y = y1 + y2 + y3 + y4 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.sanity_tol, solver=pinv_solver, 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 += l_sqrt.dot(tm.eps_r_noop(y_pi, A, Vri_)) 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