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 test_ground_state_matches(self, dense, MPO_ham): h = MPO_ham(6) dmrg = DMRG1(h, bond_dims=8) dmrg.opts['eff_eig_dense'] = dense assert dmrg.solve() 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) h_dense = h.to_dense() # check against dense form actual_e, gs = seigsys(h_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(6, cyclic=False, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(6, cyclic=False) actual_e, gs = seigsys(ham_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0)
def test_ising_model_with_field(self, cyclic): p = qtn.MPS_computational_state('0000100000', cyclic=cyclic) pd = p.to_dense() H_nni = qtn.NNI_ham_ising(10, j=4, bx=1, cyclic=cyclic) H_mpo = qtn.MPO_ham_ising(10, j=4, bx=1, cyclic=cyclic) H = qu.ham_ising(10, jz=4, bx=1, cyclic=cyclic) tebd = qtn.TEBD(p, H_nni, tol=1e-6) tebd.split_opts['cutoff'] = 1e-9 tebd.split_opts['cutoff_mode'] = 'rel' evo = qu.Evolution(pd, H) e0 = qu.expec(pd, H) e0_mpo = qtn.expec_TN_1D(p.H, H_mpo, p) assert e0_mpo == pytest.approx(e0) tf = 2 ts = np.linspace(0, tf, 21) evo.update_to(tf) for pt in tebd.at_times(ts): assert isinstance(pt, qtn.MatrixProductState) assert (pt.H @ pt) == pytest.approx(1.0, rel=1e-5) assert (qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0, rel=1e-5)) ef_mpo = qtn.expec_TN_1D(tebd.pt.H, H_mpo, tebd.pt) assert ef_mpo == pytest.approx(e0, 1e-5)
def test_matches_exact(self, dense, MPO_ham): h = MPO_ham(6) dmrg = DMRG2(h, bond_dims=8) assert dmrg._k.site[0].dtype == float dmrg.opts['eff_eig_dense'] = dense assert dmrg.solve() # XXX: need to dispatch SLEPc seigsys on real input # assert dmrg._k.site[0].dtype == float 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) h_dense = h.to_dense() # check against dense form actual_e, gs = seigsys(h_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0) # check against actual MPO_ham if MPO_ham is MPO_ham_XY: ham_dense = ham_heis(6, cyclic=False, j=(1.0, 1.0, 0.0)) elif MPO_ham is MPO_ham_heis: ham_dense = ham_heis(6, cyclic=False) actual_e, gs = seigsys(ham_dense, k=1) assert_allclose(actual_e, eff_e) assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0)
def test_simple(self): Z = qu.pauli('Z') P = qu.projector(Z & Z) uu = qu.dop(qu.up()) & qu.dop(qu.up()) dd = qu.dop(qu.down()) & qu.dop(qu.down()) assert_allclose(P, uu + dd) assert qu.expec(P, qu.bell_state('phi+')) == pytest.approx(1.0) assert qu.expec(P, qu.bell_state('psi+')) == pytest.approx(0.0)
def test_bell_states(self): for s, dic in zip(("psi-", "psi+", "phi+", "phi-"), ({ "qtype": 'dop' }, {}, { "sparse": True }, {})): p = bell_state(s, **dic) assert_allclose(expec(p, p), 1.0) pa = ptr(p, [2, 2], 0) assert_allclose(expec(pa, pa), 0.5)
def test_depolarize(self, stack): rho = qu.rand_rho(2) I, X, Y, Z = (qu.pauli(s) for s in 'IXYZ') es = [qu.expec(rho, A) for A in (X, Y, Z)] p = 0.1 Ek = [(1 - p)**0.5 * I, (p / 3)**0.5 * X, (p / 3)**0.5 * Y, (p / 3)**0.5 * Z] if stack: Ek = np.stack(Ek, axis=0) sigma = qu.kraus_op(rho, Ek, check=True) es2 = [qu.expec(sigma, A) for A in (X, Y, Z)] assert qu.tr(sigma) == pytest.approx(1.0) assert all(abs(e2) < abs(e) for e, e2 in zip(es, es2)) sig_exp = sum(E @ rho @ qu.dag(E) for E in Ek) assert_allclose(sig_exp, sigma)
def test_works(self, sz): prj = zspin_projector(4, sz) h = ham_heis(4) h0 = prj @ h @ prj.H v0s = eigvecs(h0) for v0 in v0s.T: vf = prj.H @ v0.T prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = groundstate(h) gs0 = prj .H @ v0s[:, 0] assert_allclose(expec(gs, gs0), 1.0) assert_allclose(expec(h, gs0), expec(h, gs))
def test_spin_half_double_space(self, sz): prj = qu.zspin_projector(5, sz) h = qu.ham_heis(5) h0 = prj.T @ h @ prj v0s = qu.eigvecsh(h0) for v0 in v0s.T: vf = prj @ v0.T prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = qu.groundstate(h) gs0 = prj @ v0s[:, 0] assert_allclose(qu.expec(gs, gs0), 1.0) assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
def test_evolve_obc(self, order, dt, tol): n = 10 tf = 2 psi0 = qtn.MPS_neel_state(n) H_int = qu.ham_heis(2, cyclic=False) if dt and tol: with pytest.raises(ValueError): qtn.TEBD(psi0, H_int, dt=dt, tol=tol) return tebd = qtn.TEBD(psi0, H_int, dt=dt, tol=tol) tebd.split_opts['cutoff'] = 0.0 if (dt is None and tol is None): with pytest.raises(ValueError): tebd.update_to(tf, order=order) return tebd.update_to(tf, order=order) assert tebd.t == approx(tf) assert not tebd._queued_sweep dpsi0 = psi0.to_dense() dham = qu.ham_heis(n=n, sparse=True, cyclic=False) evo = qu.Evolution(dpsi0, dham) evo.update_to(tf) assert qu.expec(evo.pt, tebd.pt.to_dense()) == approx(1, rel=1e-5)
def get_crossing(ghz_state: BaseGHZState, geometry: BaseGeometry, N: int, V: float): ghz_1 = ghz_state._get_components()[1] Delta_range = np.linspace(-characteristic_V * 5, characteristic_V * 5, 50) s_qs = StaticQubitSystem( N=N, V=V, geometry=geometry, Omega=0, Delta=Delta_range, ) energies = [] for detuning in Delta_range: H = s_qs.get_hamiltonian(detuning) energy = q.expec(H, ghz_1).real energies.append(energy) energies = np.array(energies) def find_root(x: np.ndarray, y: np.ndarray): """ Finds crossing (where y equals 0), given that x, y is roughly linear. """ if (y == 0).all(): return np.nan _right_bound = (y < 0).argmax() _left_bound = _right_bound - 1 crossing = y[_left_bound] / (y[_left_bound] - y[_right_bound]) \ * (x[_right_bound] - x[_left_bound]) + x[_left_bound] return crossing crossing = find_root(Delta_range, energies) print(f"Found crossing: {crossing:.3e}") return crossing
def test_expm_krylov_expokit(self): ham = rand_herm(100, sparse=True, density=0.8) psi = rand_ket(100) evo_exact = QuEvo(psi, ham, method='solve') evo_krylov = QuEvo(psi, ham, method='expm', expm_backend='slepc-krylov') evo_expokit = QuEvo(psi, ham, method='expm', expm_backend='slepc-expokit') ts = np.linspace(0, 100, 21) for p1, p2, p3 in zip(evo_exact.at_times(ts), evo_krylov.at_times(ts), evo_expokit.at_times(ts)): assert abs(expec(p1, p2) - 1) < 1e-9 assert abs(expec(p1, p3) - 1) < 1e-9
def test_seigsys_slepc_eigvecs(self): h = rand_herm(100, sparse=True, density=0.2) lks, vks = seigsys_slepc(h, k=5) lka, vka = seigsys(h, k=5) assert vks.shape == vka.shape for ls, vs, la, va in zip(lks, vks.T, lka, vka.T): assert_allclose(ls, la) assert_allclose(expec(vs, va), 1.0)
def test_from_dense(self): psi = qu.rand_ket(2**8) mps = MatrixProductState.from_dense(psi, dims=[2] * 8) assert mps.tags == {'I{}'.format(i) for i in range(8)} assert mps.site_inds == tuple('k{}'.format(i) for i in range(8)) assert mps.nsites == 8 mpod = mps.to_dense() assert qu.expec(mpod, psi) == pytest.approx(1)
def test_half_filling_groundstate(self): H = qu.ham_hubbard_hardcore(8, t=0.5, V=1.0, mu=1.0) gs = qu.groundstate(H) dims = [2] * 8 cn = qu.num(2) ens = [qu.expec(cn, qu.ptr(gs, dims, i)) for i in range(8)] for en in ens: assert en == pytest.approx(0.5, rel=1e-6)
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 test_works(self, sz): prj = qu.zspin_projector(4, sz) h = qu.ham_heis(4) h0 = prj.T @ h @ prj v0s = qu.eigvecsh(h0) for i in range(v0s.shape[1]): v0 = v0s[:, [i]] vf = prj @ v0 prjv = vf @ vf.H # Check reconstructed full eigenvectors commute with full ham assert_allclose(prjv @ h, h @ prjv, atol=1e-13) if sz == 0: # Groundstate must be in most symmetric subspace gs = qu.groundstate(h) gs0 = prj @ v0s[:, [0]] assert_allclose(qu.expec(gs, gs0), 1.0) assert_allclose(qu.expec(h, gs0), qu.expec(h, gs))
def test_evo_at_times(self): ham = qu.ham_heis(2, cyclic=False) p0 = qu.up() & qu.down() sim = qu.Evolution(p0, ham, method='solve') ts = np.linspace(0, 10) for t, pt in zip(ts, sim.at_times(ts)): x = cos(t) y = qu.expec(pt, qu.ikron(qu.pauli('z'), [2, 2], 0)) assert_allclose(x, y, atol=1e-15)
def test_quevo_at_times(self): ham = ham_heis(2, cyclic=False) p0 = up() & down() sim = QuEvo(p0, ham, method='solve') ts = np.linspace(0, 10) for t, pt in zip(ts, sim.at_times(ts)): x = cos(t) y = expec(pt, eyepad(pauli('z'), [2, 2], 0)) assert_allclose(x, y, atol=1e-15)
def state_local_occs(self, qstate=None, k=0, faces=False): ''' TODO: fix face shapes? Expectation values <k|local fermi occupation|k> in the kth excited eigenstate, at vertex sites (and faces if specified). param qstate: vector in full qubit basis param k: if `state` isn't specified, will compute for the kth excited energy eigenstate (defaults to ground state) param faces: if True, return occupations at face qubits as well Returns: local occupations `nocc_v`, (`nocc_f`) nocc_v (ndarray, shape (Lx,Ly)) nocc_f (ndarray, shape (Lx-1,Ly-1)) ''' if qstate is None: qstate = self._eigstates[:, k] #local number ops acting on each site j # Nj = self.site_number_ops(sites=self.all_sites() , fermi=False) Nj = [ qu.ikron(self.number_op(), self._sim_dims, [site]) for site in self.all_sites() ] #expectation <N> for each vertex nocc_v = np.array([ qu.expec(Nj[v], qstate) for v in self.vertex_sites() ]).reshape(self._lat_shape) if not faces: return nocc_v #expectation <Nj> for each face nocc_f = np.array([qu.expec(Nj[f], qstate) for f in self.face_sites()]) return nocc_v, nocc_f
def state_occs(self, state): Nk = [ qu.ikron(number_op(), self._dims, [site]) for site in self._V_ind.flatten() ] n_ij = np.real( np.array([qu.expec(Nk[k], state) for k in range(self._N)])).reshape(self._shape) return n_ij
def test_expm_slepc(self, expm_backend): ham = qu.ham_mbl(7, dh=0.5, sparse=True) psi = qu.rand_ket(2**7) evo_exact = qu.Evolution(psi, ham, method='solve') evo_slepc = qu.Evolution(psi, ham, method='expm', expm_backend=expm_backend) ts = np.linspace(0, 100, 6) for p1, p2 in zip(evo_exact.at_times(ts), evo_slepc.at_times(ts)): assert abs(qu.expec(p1, p2) - 1) < 1e-9
def test_insert_operator(self): p = MPS_rand_state(3, 7, tags='KET') q = p.H.retag({'KET': 'BRA'}) qp = q & p sz = qu.spin_operator('z').real qp.insert_operator(sz, ('KET', 'I1'), ('BRA', 'I1'), tags='SZ', inplace=True) assert 'SZ' in qp.tags assert len(qp.tensors) == 7 x1 = qp ^ all x2 = qu.expec(p.to_dense(), qu.ikron(sz, [2, 2, 2], inds=1)) assert x1 == pytest.approx(x2)
def test_construct(self, gate, dtype, sparse): if gate in ('Rx', 'Ry', 'Rz', 'phase_gate'): args = (0.43827, ) elif gate in ('U_gate'): args = (0.1, 0.2, 0.3) else: args = () G = getattr(qu, gate)(*args, dtype=dtype, sparse=sparse) assert G.dtype == dtype assert qu.issparse(G) is sparse psi = qu.rand_ket(G.shape[0]) Gpsi = G @ psi assert qu.expec(Gpsi, Gpsi) == pytest.approx(1.0)
def test_prepare_GHZ(self): qc = qtn.Circuit(3) gates = [ ('H', 0), ('H', 1), ('CNOT', 1, 2), ('CNOT', 0, 2), ('H', 0), ('H', 1), ('H', 2), ] qc.apply_circuit(gates) assert qu.expec(qc.psi.to_dense(), qu.ghz_state(3)) == pytest.approx(1)
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_compute_local_expectation_vs_dense(self, Lx, Ly, normalized): # (2Lx-1) * (2Ly-1) lattice ePEPSvector epeps = qnets.QubitEncodeVector.rand(Lx, Ly)\ .convert_to_ePEPS_vector() # qubits + dummies n_sites = (2 * Lx - 1) * (2 * Ly - 1) # vertices + occupied faces in 'original' Lx*Ly lattice n_qubits = (Lx * Ly) + int((Lx - 1) * (Ly - 1) / 2) # 'qubit' Fermi-Hubbard with random parameters t, V, mu = np.random.rand(3) H = hams.SpinlessSimHam(Lx, Ly, t, V, mu) # separate indices of qubits from 'aux' tensors qubit_inds = tuple( starmap(epeps.site_ind, (epeps.qubit_to_coo_map[q] for q in range(n_qubits)))) non_qubit_inds = set(epeps.site_inds) - set(qubit_inds) # 'densify' into vector with qubit dimensions first psi_dense = epeps.to_dense((*qubit_inds, *non_qubit_inds)) if normalized: qu.normalize(psi_dense) dense_terms = [ qu.pkron(term, dims=[2] * n_sites, inds=where) for where, term in H.gen_ham_terms() ] exact = sum((qu.expec(h, psi_dense) for h in dense_terms)) # now compute energy with `ePEPSvector.compute_local_expectation` q2coo = lambda q: epeps.qubit_to_coo_map[q] CooHam = H.convert_to_coordinate_ham(q2coo) terms = CooHam._coo_ham_terms envs, plaqmap = epeps.calc_plaquette_envs_and_map(terms) opts = dict(cutoff=2e-3, max_bond=9, contract_optimize='random-greedy') e = epeps.compute_local_expectation(terms, normalized=normalized, autogroup=False, plaquette_envs=envs, plaquette_map=plaqmap, **opts) assert e == pytest.approx(exact, rel=1e-2)
def test_NNI_and_single_site_terms_heis(self): n = 10 psi0 = qtn.MPS_neel_state(n) H_nni = qtn.NNI_ham_heis(n, j=(0.7, 0.8, 0.9), bz=0.337) tebd = qtn.TEBD(psi0, H_nni) tebd.update_to(1.0, tol=1e-5) assert abs(psi0.H @ tebd.pt) < 1.0 assert tebd.pt.entropy(5) > 0.0 psi0_dns = qu.neel_state(n) H_dns = qu.ham_heis(10, j=(0.7, 0.8, 0.9), b=0.337, cyclic=False) evo = qu.Evolution(psi0_dns, H_dns) evo.update_to(1.0) assert qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0)
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_NNI_and_single_site_terms(self): n = 10 psi0 = qtn.MPS_neel_state(n) H_nni = qtn.NNI_ham_XY(n, bz=0.9) assert H_nni.special_sites == {(8, 9)} tebd = qtn.TEBD(psi0, H_nni) tebd.update_to(1.0, tol=1e-5) assert abs(psi0.H @ tebd.pt) < 1.0 assert tebd.pt.entropy(5) > 0.0 psi0_dns = qu.neel_state(n) H_dns = qu.ham_XY(10, jxy=1.0, bz=0.9, cyclic=False) evo = qu.Evolution(psi0_dns, H_dns) evo.update_to(1.0) assert qu.expec(tebd.pt.to_dense(), evo.pt) == pytest.approx(1.0)