def test_ground_state_matches(self, dense, MPO_ham, cyclic): n = 10 tol = 3e-2 if cyclic else 1e-4 h = MPO_ham(n, cyclic=cyclic) dmrg = DMRG1(h, bond_dims=[4, 8, 12]) dmrg.opts['local_eig_ham_dense'] = dense dmrg.opts['periodic_segment_size'] = 1.0 dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6 assert dmrg.solve(tol=tol / 10, verbosity=1) assert dmrg.state.cyclic == cyclic eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0, rtol=tol) h_dense = h.to_dense() # check against dense form actual_e, gs = eigh(h_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(n, cyclic=cyclic, j=(1.0, 1.0, 0.0), sparse=True) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(n, cyclic=cyclic, sparse=True) actual_e, gs = eigh(ham_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
def two_qubit_eigsectors(strA='XY', strB='YX'): ''' Params: strA, strB [strings] Action of stabilizers on face-qubit subspace. Return: `eigsectors` [ndarray(shape=(2,2), dtype=object)] Each element of eigsector contains the unique vector in the face-qubit subspace that diagonalizes strA, strB with respective eigenvalues +/-1. eigsectors[0,0]: +1, +1 eigsectors[0,1]: +1, -1 eigsectors[1,0]: -1, +1 eigsectors[1,1]: -1, -1 ''' sign_dic = {0: 1.0, 1: -1.0} X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i']) opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I} face_dims = [2]*2 #dimensions of face-qubit subspace # ### # strA = 'XY' # strB = 'YX' # ### SA = qu.kron(*[opmap[Q] for Q in strA]) SB = qu.kron(*[opmap[Q] for Q in strB]) # SA, SB = X&Y, Y&X eigsectors = np.ndarray(shape=face_dims, dtype=object) eva, Ua = qu.eigh(SA) for indA, signA in sign_dic.items(): #pick evectors in (signA) sector Ua_sgn = Ua[:, np.isclose(eva, signA)] #4x2 #Stabilizer B on (signA) eigspace of SA Qb = Ua_sgn.H @ SB @ Ua_sgn evb, Ub = qu.eigh(Qb) for indB, signB in sign_dic.items(): #pick evector in signB sector Ub_sgn = Ub[:,np.isclose(evb, signB)] #2x1 face_state = Ua_sgn @ Ub_sgn #4x1 assert np.allclose(SA@face_state, signA*face_state) assert np.allclose(SB@face_state, signB*face_state) eigsectors[indA,indB] = face_state return eigsectors
def test_eigh(self): H = qu.ham_mbl(6, dh=2.5) a_el, a_ev = qu.eigh(H, autoblock=False) el, ev = qu.eigh(H, autoblock=True) assert qu.norm(ev @ qu.ldmul(el, ev.H) - H, 'fro') < 1e-12 assert_allclose(a_el, el) assert_allclose(ev.H @ ev, np.eye(H.shape[0]), atol=1e-12)
def test_thermal_state_tuple(self): full = rand_herm(2**4) l, v = eigh(full) for beta in (0, 0.5, 1, 10): rhoth1 = thermal_state(full, beta) rhoth2 = thermal_state((l, v), beta) assert_allclose(rhoth1, rhoth2)
def test_project_eig(self, backend): Hl = qu.Lazy(qu.ham_heis, 4, sparse=True, shape=(16, 16)) Pl = qu.Lazy(qu.zspin_projector, 4, shape=(16, 6)) ge, gs = qu.eigh(Hl, P=Pl, k=1, backend=backend) assert ge == pytest.approx(-2) assert qu.expec(gs, gs) == pytest.approx(1.0)
def solve_ED(self): ''' Solves full spectrum of simulator Hamiltonian, stores eigensystem. Assumes self._HamSim exists. ''' self._eigens, self._eigstates = qu.eigh(self._HamCode)
def test_eigsys(self, mat_herm_dense): u, a = mat_herm_dense evals, v = qu.eigh(a) assert(set(np.rint(evals)) == set((-1, 2, 4, -3))) assert_allclose(evals, [-3, -1, 2, 4]) for i, j in zip([3, 0, 1, 2], range(4)): o = u[:, [i]].H @ v[:, [j]] assert_allclose(abs(o), 1.)
def test_cross_equality(self, mat_herm_sparse, k, which): _, a = mat_herm_sparse sigma = 1 if which in {None, "TR"} else None lks, vks = zip(*(qu.eigh(a, k=k, which=which, sigma=sigma, backend=b) for b in eigs_backends)) lks, vks = tuple(lks), tuple(vks) for i in range(len(lks) - 1): assert_allclose(lks[i], lks[i + 1]) assert_allclose(abs(vks[i].H @ vks[i + 1]), qu.eye(k), atol=1e-14)
def test_exp_sparse(self): a = rand_herm(100, sparse=True, density=0.1) k = rand_ket(100) out = mfn_multiply_slepc(a, k) al, av = eigh(a.A) expected = av @ np.diag(np.exp(al)) @ av.conj().T @ k assert_allclose(out, expected)
def test_eigs_slepc_eigvecs(self, dtype): h = rand_herm(32, sparse=True, density=0.5) if dtype == 'real': h = h.real lks, vks = eigs_slepc(h, k=5) lka, vka = eigh(h, k=5, backend='scipy') assert vks.shape == vka.shape assert h.dtype == vks.dtype assert_allclose(lks, lka) assert_allclose(abs(vka.H @ vks), np.eye(5), atol=1e-8)
def test_eigs_sparse_wvecs(self, mat_herm_sparse, backend): u, a = mat_herm_sparse assert qu.issparse(a) lk, vk = qu.eigh(a, k=2, backend=backend) assert_allclose(lk, (-3, -1)) for i, j in zip([3, 0], [0, 1]): o = u[:, [i]].H @ vk[:, [j]] assert_allclose(abs(o), 1.) vk = qu.eigvecsh(a, k=2, backend=backend) for i, j in zip([3, 0], [0, 1]): o = u[:, [i]].H @ vk[:, [j]] assert_allclose(abs(o), 1.)
def test_1(self): a = rand_herm(100, sparse=True) el, ev = eigh(a.A) which = abs(el) < 0.2 el, ev = el[which], ev[:, which] offset = norm(a, 'fro') a = a + offset * sp.eye(a.shape[0]) sl, sv = eigs_slepc(a, k=6, l_win=(-0.2 + offset, 0.2 + offset)) sl -= offset assert_allclose(el, sl) assert_allclose(np.abs(sv.H @ ev), np.eye(el.size), atol=1e-11)
def test_matches_exact(self, dense, MPO_ham, cyclic): n = 6 h = MPO_ham(n, cyclic=cyclic) tol = 3e-2 if cyclic else 1e-4 dmrg = DMRG2(h, bond_dims=[4, 8, 12]) assert dmrg._k[0].dtype == float dmrg.opts['local_eig_ham_dense'] = dense dmrg.opts['periodic_segment_size'] = 1.0 dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6 assert dmrg.solve(tol=tol / 10, verbosity=1) # XXX: need to dispatch SLEPc eigh on real input # assert dmrg._k[0].dtype == float eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(expec(mps_gs_dense, mps_gs_dense), 1.0, rtol=tol) h_dense = h.to_dense() # check against dense form actual_e, gs = eigh(h_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(n, cyclic=cyclic, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(n, cyclic=cyclic) actual_e, gs = eigh(ham_dense, k=1) assert_allclose(actual_e, eff_e, rtol=tol) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
def test_expm_multiply(self, num_workers, bigsparsemat, big_vec): a = bigsparsemat k = big_vec if ((num_workers is not None) and ALREADY_RUNNING_AS_MPI and num_workers > 1 and num_workers != NUM_MPI_WORKERS): with pytest.raises(ValueError): mfn_multiply_slepc_spawn(a, k, num_workers=num_workers) else: out = mfn_multiply_slepc_spawn(a, k, num_workers=num_workers) al, av = eigh(a.A) expected = av @ np.diag(np.exp(al)) @ av.conj().T @ k assert_allclose(out, expected)
def test_sqrt_sparse(self): import scipy.sparse as sp a = rand_pos(32, sparse=True, density=0.1) a = a + 0.001 * sp.eye(32) k = rand_ket(32) out = mfn_multiply_slepc(a, k, fntype='sqrt', isherm=True) al, av = eigh(a.A) al[al < 0] = 0.0 # very small neg values spoil sqrt expected = av @ np.diag(np.sqrt(al)) @ av.conj().T @ k assert_allclose(out, expected, rtol=1e-6)
def test_ising_and_MPS_product_state(self): h = MPO_ham_ising(6, bx=2.0, j=0.1) dmrg = DMRG1(h, bond_dims=8) assert dmrg.solve(verbosity=1) eff_e, mps_gs = dmrg.energy, dmrg.state mps_gs_dense = mps_gs.to_dense() assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0) # check against dense h_dense = h.to_dense() actual_e, gs = eigh(h_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0) exp_gs = MPS_product_state([plus()] * 6) assert_allclose(abs(exp_gs.H @ mps_gs), 1.0, rtol=1e-3)
def test_evo_ham_dense_ket_solve(self, ham_rcr_psi, sparse, presolve): ham, trc, p0, tm, pm = ham_rcr_psi ham = qu(ham, sparse=sparse) if presolve: l, v = eigh(ham) sim = Evolution(p0, (l, v)) assert sim._solved else: sim = Evolution(p0, ham, method='solve') sim.update_to(tm) assert_allclose(sim.pt, pm) assert expec(sim.pt, p0) < 1.0 sim.update_to(trc) assert_allclose(sim.pt, p0) assert isinstance(sim.pt, np.matrix) assert sim.t == trc
def test_evo_ham_dense_ket_solve(self, ham_rcr_psi, sparse, presolve): ham, trc, p0, tm, pm = ham_rcr_psi ham = qu.qu(ham, sparse=sparse) if presolve: l, v = qu.eigh(ham) sim = qu.Evolution(p0, (l, v)) assert isinstance(sim._ham, tuple) and len(sim._ham) == 2 else: sim = qu.Evolution(p0, ham, method='solve') sim.update_to(tm) assert_allclose(sim.pt, pm) assert qu.expec(sim.pt, p0) < 1.0 sim.update_to(trc) assert_allclose(sim.pt, p0) assert isinstance(sim.pt, qu.qarray) assert sim.t == trc
def projected_ham_3(self): ''' Should be equivalent to self.ham_code() ''' #X because stabilizer acts with X on 7th qubit _, Ux = qu.eigh(qu.pauli('x')) U = qu.ikron(Ux.copy(), dims=self._sim_dims, inds=[6]) Stilde = (U.H @ self.stabilizer() @ U).real.round() #Stilde should be diagonal! U_plus = U[:, np.where(np.diag(Stilde) == 1.0)[0]] HamProj = U_plus.H @ self.ham_sim() @ U_plus return HamProj #in +1 stabilizer eigenbasis
def make_stabilizer(self): ''' DEPREC -- DON'T USE TODO: * add a projector onto codespace (see method 2) * generalize indices, rotation, reshape, etc * always need to round? check always real ''' X, Z = (qu.pauli(mu) for mu in ['x', 'z']) ## TODO: make general # ops = [Z,Z,Z,Z,X] # inds = [1,2,4,5,6] # stabilizer = qu.ikron(ops=ops, dims=self._sim_dims, inds=inds) _, Ux = qu.eigh(qu.pauli('x')) stab_data = self.loop_stabilizer_data(0, 1) oplist = [qu.pauli(Q) for Q in stab_data['opstring']] stabilizer = qu.ikron(ops=oplist, dims=self._sim_dims, inds=stab_data['inds']) #TODO: change to general rather than inds=6, Ux U = qu.ikron(Ux.copy(), dims=self._sim_dims, inds=[6]) #TODO: can this be done without rounding()/real part? Stilde = (U.H @ stabilizer @ U).real.round() assert is_diagonal(Stilde) U_plus = U[:, np.where(np.diag(Stilde) == 1.0)[0]] HamCode = U_plus.H @ self.ham_sim() @ U_plus self._stabilizer = stabilizer self._Uplus = U_plus #+1 eigenstates written in full qubit basis self._HamCode = HamCode # in +1 stabilizer eigenbasis
def test_explicit_sweeps(self): n = 8 chi = 16 ham = MPO_ham_mbl(n, dh=4, seed=42) p0 = MPS_rand_state(n, 2).expand_bond_dimension(chi) b0 = p0.H align_TN_1D(p0, ham, b0, inplace=True) en0 = (p0 & ham & b0) ^ ... dmrgx = DMRGX(ham, p0, chi) dmrgx.sweep_right() en1 = dmrgx.sweep_left(canonize=False) assert en0 != en1 dmrgx.sweep_right(canonize=False) en = dmrgx.sweep_right(canonize=True) # check normalized assert_allclose(dmrgx._k.H @ dmrgx._k, 1.0) k = dmrgx._k.to_dense() h = ham.to_dense() el, ev = eigh(h) # check variance very low assert np.abs((k.H @ h @ h @ k) - (k.H @ h @ k)**2) < 1e-12 # check exactly one eigenvalue matched well assert np.sum(np.abs(el - en) < 1e-12) == 1 # check exactly one eigenvector is matched with high fidelity ovlps = (ev.H @ k).A**2 big_ovlps = ovlps[ovlps > 1e-12] assert_allclose(big_ovlps, [1]) # check fully assert is_eigenvector(k, h, atol=1e-12, rtol=1e-12)
LOSCH_ETH = np.array(-np.log(evo_ETH.results['losch'])) / N ### MBL --> ETH ### W_i = params.W_i J_MBL = (0.0, 0.0, 0.0) H_MBL = P.T @ qu.ham_mbl(N, W_i, J_MBL, cyclic=False, dh_dist='qp', beta=0.721, seed=seed, sparse=True).real @ P Psi_MBL = qu.eigh(H_MBL, k=1, which='SA')[1] J_evo2 = (J, J, J) H_evo2 = P.T @ qu.ham_mbl(N, W, J_evo2, cyclic=False, dh_dist='qp', beta=0.721, seed=seed, sparse=True).real @ P compute = { 'time': lambda t, p: t, 'losch': lambda t, p: qu.fidelity(Psi_MBL, p)
def solveED(self): '''Diagonalize codespace Ham, store eigensystem. ''' self._eigens, self._eigstates = qu.eigh(self._HamCode)
def one_qubit_U_matrices(qlattice, empt_face_coo): ''' TODO: check parity more intelligently U matrix for lifting states from 'Fock' space to 'Stab' subspace of Simulator space. empt_face_coo: tuple (x,y) location of empty face corresponding to the loop stabilizer operator. ''' assert qlattice._faces[empt_face_coo] is None X, Y, Z = (qu.pauli(mu) for mu in ['x','y','z']) opmap = {'X':X, 'Y':Y, 'Z':Z} #number of fermionic/qubit DOF Nfermi = qlattice._Nfermi Nqubit = qlattice._Nsites #dimensions of simulator space [2,2,...] sim_space_dims = qlattice._sim_dims code_space_dims = qlattice._encoded_dims #sites and action-string of stabilizer operator stab_data = qlattice.loop_stabilizer_data(*empt_face_coo) arrays = [opmap[Q] for Q in stab_data['opstring']] #(this is only for one-face-qubit stabilizers) assert len(arrays) == 4+1 inds = stab_data['inds'] # stabilizer = qu.ikron( ops=arrays, # dims=sim_space_dims, # inds=inds) #action on just the face qubit, either X or Y face_op = arrays[4] elx, evx = qu.eigh(face_op) #diagonalized the face qubit eigenfaces = {-1 : evx[:,0], +1 : evx[:,1]} #II..ZZZZ..III parity-check the vertices of face-loop corner_parity_op = qu.ikron(ops=arrays[:4], dims=code_space_dims, inds=inds[:4]) #get all the stabilizer eigenvectors Uplus = np.zeros((2**Nqubit, 2**Nfermi)) Uplus_dagger = np.zeros((2**Nfermi, 2**Nqubit)) for i in range(2**Nfermi): vertex_state_i = qu.basis_vec(i=i, dim=2**Nfermi) sign = qu.expec(corner_parity_op, vertex_state_i) face_state_i = eigenfaces[int(sign)].reshape(-1,1) full_state_i = vertex_state_i & face_state_i Uplus[:,i] = full_state_i.flatten() Uplus_dagger[i,:] = full_state_i.H.flatten() # if not tensorize: return qu.qu(Uplus), qu.qu(Uplus_dagger)
def three_qubit_U_matrix(qlattice, qstabs=None): ''' TODO: *define SX_vert (vertices acted on by Z-stabilizer) ''' sectors = {1.0: 0, -1.0: 1} X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i']) opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I} face_dims = [2]*3 #dimensions of face-qubit subspace if qstabs==None: qstab_A = loopStabOperator( vert_inds=[1,2,5,4], face_op_str='XYI', face_inds=[12,13,14]) qstab_B = loopStabOperator( vert_inds=[3,4,7,6], face_op_str='YXY', face_inds=[12,13,14]) qstab_C = loopStabOperator( vert_inds=[7,8,11,10], face_op_str='IYX', face_inds=[12,13,14]) SA = qu.kron(*[opmap[Q] for Q in qstab_A.face_op_str]) SB = qu.kron(*[opmap[Q] for Q in qstab_B.face_op_str]) SC = qu.kron(*[opmap[Q] for Q in qstab_C.face_op_str]) # SA, SB, SC = X&Y&I, Y&X&Y, I&Y&X eigfaces = np.ndarray(shape=face_dims, dtype=object) for signA, indA in sectors.items(): eva, Ua = qu.eigh(SA) Ua_sector = Ua[:,eva==signA] #8x4 Qb = Ua_sector.H @ SB @ Ua_sector # Qc = Ua_sector.H @ SC @ Ua_sector evb, Ub = qu.eigh(Qb) for signB, indB in sectors.items(): Ub_sector = Ub[:, np.isclose(evb,signB)] #4x2 #SC on b-eigenspace Qc = Ub_sector.H @ Ua_sector.H @ SC @ Ua_sector @ Ub_sector #2x2 evc, Uc = qu.eigh(Qc) for signC, indC in sectors.items(): #should be in a 1-dimensional subspace now vec = Uc[:,np.isclose(evc,signC)] #vector in 8-dim face qubit space face_vec = Ua_sector @ Ub_sector @ vec assert np.allclose(SA@face_vec, signA*face_vec) assert np.allclose(SB@face_vec, signB*face_vec) assert np.allclose(SC@face_vec, signC*face_vec) eigfaces[indA,indB,indC] = face_vec Nfermi, Nqubit = qlattice._Nfermi, qlattice._Nsites code_dims = [2]*Nfermi #vertices qub_dims = [2]*Nqubit #vertices&faces ####### qindices_A = qstab_A.vert_inds qindices_B = qstab_B.vert_inds qindices_C = qstab_C.vert_inds ####### #parts of stabilizers acting only on vertex qubits SA_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_A, dims=code_dims) SB_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_B, dims=code_dims) SC_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_C, dims=code_dims) Uplus = np.ndarray(shape=(2**Nqubit, 2**Nfermi)) print('here') for k in range(2**Nfermi): print(k%10) #state of vertex qubits, all local z-eigenstates vertex_state = qu.basis_vec(i=k, dim=2**Nfermi) secA = sectors[qu.expec(SA_vert, vertex_state)] secB = sectors[qu.expec(SB_vert, vertex_state)] secC = sectors[qu.expec(SC_vert, vertex_state)] face_state = eigfaces[secA, secB, secC] full_state = vertex_state & face_state #"stable" eigenstate written in qubit basis Uplus[:,k] = full_state.flatten() #full_state should be +1 eigenstate of all stabilizers assert np.allclose((SA_vert&SA) @ full_state, full_state) assert np.allclose((SB_vert&SB) @ full_state, full_state) assert np.allclose((SC_vert&SC) @ full_state, full_state) return qu.qu(Uplus)
def test_against_arpack(self): A = qu.rand_herm(32, dtype=float) lk, vk = qu.eigh(A, k=6, backend='lobpcg') slk, svk = qu.eigh(A, k=6, backend='scipy') assert_allclose(lk, slk) assert_allclose(np.eye(6), abs(vk.H @ svk), atol=1e-9, rtol=1e-9)