def test_partial_trace_early_return(self): a = qu.qu([0.5, 0.5, 0.5, 0.5], 'ket') b = qu.partial_trace(a, [2, 2], [0, 1]) assert_allclose(a @ a.H, b) a = qu.qu([0.5, 0.5, 0.5, 0.5], 'dop') b = qu.partial_trace(a, [2, 2], [0, 1]) assert_allclose(a, b)
def test_partial_trace_return_type(self): a = qu.qu([0, 2**-0.5, 2**-0.5, 0], 'ket') b = qu.partial_trace(a, [2, 2], 1) assert (type(b) == qu.qarray) a = qu.qu([0, 2**-0.5, 2**-0.5, 0], 'dop') b = qu.partial_trace(a, [2, 2], 1) assert (type(b) == qu.qarray)
def test_partial_trace_return_type(self): a = qu([0, 2**-0.5, 2**-0.5, 0], 'ket') b = partial_trace(a, [2, 2], 1) assert(type(b) == np.matrix) a = qu([0, 2**-0.5, 2**-0.5, 0], 'dop') b = partial_trace(a, [2, 2], 1) assert(type(b) == np.matrix)
def test_normalized(self): x = [3j, 4j] p = qu.qu(x, 'k', normalized=False) assert_almost_equal(qu.tr(p.H @ p), 25.) p = qu.qu(x, 'k', normalized=True) assert_almost_equal(qu.tr(p.H @ p), 1.) p = qu.qu(x, 'dop', normalized=True) assert_almost_equal(qu.tr(p), 1.)
def test_chop_inplace_dop(self): a = qu.qu([1, 0.1], 'dop') qu.chop(a, tol=0.11, inplace=True) assert_allclose(a, qu.qu([1, 0], 'dop')) a = qu.qu([1, 0.1], 'dop', sparse=True) qu.chop(a, tol=0.11, inplace=True) b = qu.qu([1, 0.0], 'dop', sparse=True) assert ((a != b).nnz == 0)
def test_sparse_create(self): x = [[1, 0], [3, 0]] p = qu.qu(x, 'dop', sparse=False) assert (type(p) == qu.qarray) p = qu.qu(x, 'dop', sparse=True) assert (type(p) == sp.csr_matrix) assert (p.dtype == np.complex) assert (p.nnz == 2)
def test_vector_create(self): x = [1, 2, 3j] p = qu.qu(x, qtype='ket') assert (type(p) == qu.qarray) assert (p.dtype == np.complex) assert (p.shape == (3, 1)) p = qu.qu(x, qtype='bra') assert (p.shape == (1, 3)) assert_almost_equal(p[0, 2], -3.0j)
def test_chop_inplace(self): a = qu.qu([-1j, 0.1 + 0.2j]) qu.chop(a, tol=0.11, inplace=True) assert_allclose(a, qu.qu([-1j, 0.2j])) # Sparse a = qu.qu([-1j, 0.1 + 0.2j], sparse=True) qu.chop(a, tol=0.11, inplace=True) b = qu.qu([-1j, 0.2j], sparse=True) assert ((a != b).nnz == 0)
def test_sparse_convert_to_dop(self): x = [1, 0, 9e-16, 0, 3j] p = qu.qu(x, 'ket', sparse=True) q = qu.qu(p, 'dop', sparse=True) assert (q.shape == (5, 5)) assert (q.nnz == 9) assert_almost_equal(q[4, 4], 9.) q = qu.qu(p, 'dop', sparse=True, normalized=True) assert_almost_equal(qu.tr(q), 1.)
def test_owci(self): a = qu.qu([1, 0], qtype='op') b = qu.qu([0, 1], qtype='op') for _ in (0, 1, 2, 3): p = qu.rand_product_state(2) ci = qu.one_way_classical_information(p @ p.H, [a, b]) assert_allclose(ci, 0., atol=1e-12) for i in (0, 1, 2, 3): p = qu.bell_state(i) ci = qu.one_way_classical_information(p @ p.H, [a, b]) assert_allclose(ci, 1., atol=1e-12)
def q_number_op(self): ''' Single-qubit operator, equiv. to fermionic number on a single spin sector. ''' return qu.qu([[0, 0], [0, 1]])
def test_quevo_multi_compute(self, method, qtype): ham = ham_heis(2, cyclic=False) p0 = qu(up() & down(), qtype=qtype) def some_quantity(t, _): return t def some_other_quantity(_, pt): return logneg(pt) evo = QuEvo(p0, ham, method=method, compute={ 't': some_quantity, 'logneg': some_other_quantity }) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(logneg(pt)) ts = evo.results['t'] lns = evo.results['logneg'] assert len(lns) >= len(manual_lns) # check a specific value of logneg at t=0.8 was computed automatically checked = False for t, ln in zip(ts, lns): if abs(t - 0.8) < 1e-12: assert abs(ln - manual_lns[4]) < 1e-12 checked = True assert checked
def test_convert_vector_to_dop(self): x = [1, 2, 3j] p = qu.qu(x, qtype='r') assert_allclose( p, qu.qarray([[1. + 0.j, 2. + 0.j, 0. - 3.j], [2. + 0.j, 4. + 0.j, 0. - 6.j], [0. + 3.j, 0. + 6.j, 9. + 0.j]]))
def spin_numberop(self, spin): ''' TODO: why can't use ikron()? Fermionic number operator acting on `spin` sector. ''' #which fermion-spin sector to act on? #i.e. act on qbit 0 or qbit 1? opmap = { 0: lambda: qu.qu([[0, 0], [0, 1]]) & qu.eye(2), 1: lambda: qu.eye(2) & qu.qu([[0, 0], [0, 1]]) } op = opmap[spin]() qu.core.make_immutable(op) return op
def test_dense_to_sparse_format(self, qtype, shape, out, format_out): x = [[1], [0], [2], [3j]] y = qu.qu(x, qtype=qtype, stype=format_out, sparse=True) assert y.shape == shape assert y.dtype == complex if format_out is None: format_out = "csr" assert y.format == format_out assert_allclose(y.A, out)
def test_reshape_sparse(self, qtype, shape, out, format_in, format_out): x = sparse_matrix([[1], [0], [2], [3j]], format_in) y = qu(x, qtype=qtype, stype=format_out) assert y.shape == shape assert y.dtype == complex if format_out is None: format_out = format_in assert y.format == format_out assert_allclose(y.A, out)
def test_sparse(self): i = eye(2, sparse=True) a = qu(rand_matrix(2), sparse=True) b = eyepad(a, [2, 2, 2], 1) # infer sparse assert(issparse(b)) assert_allclose(b.A, (i & a & i).A) a = rand_matrix(2) b = eyepad(a, [2, 2, 2], 1, sparse=True) # explicit sparse assert(issparse(b)) assert_allclose(b.A, (i & a & i).A)
def test_sparse(self): i = qu.eye(2, sparse=True) a = qu.qu(qu.rand_matrix(2), sparse=True) b = qu.ikron(a, [2, 2, 2], 1) # infer sparse assert (qu.issparse(b)) assert_allclose(b.A, (i & a & i).A) a = qu.rand_matrix(2) b = qu.ikron(a, [2, 2, 2], 1, sparse=True) # explicit sparse assert (qu.issparse(b)) assert_allclose(b.A, (i & a & i).A)
def number_op(self): ''' Fermionic number operator is mapped to qubit spin-down projector acting on 2-dim qbit space. n_j --> (1-Vj)/2 = (1-Zj)/2 = |down><down| ''' return qu.qu([[0, 0], [0, 1]])
def jw_creation_op(self, k): ''' Creation Jordan-Wigner qubit operator. (Z_0)x(Z_1)x ...x(Z_k-1)x |1><0|_k ''' Z = qu.pauli('z') s_plus = qu.qu([[0, 0], [1, 0]]) #|1><0| ind_list = [i for i in range(k + 1)] op_list = [Z for i in range(k)] + [s_plus] return qu.ikron(ops=op_list, dims=self._dims, inds=ind_list)
def jw_annihil_op(self, k): ''' Annihilation Jordan-Wigner qubit operator. (Z_0)x(Z_1)x ...x(Z_k-1)x |0><1|_k ''' Z = qu.pauli('z') s_minus = qu.qu([[0, 1], [0, 0]]) #|0><1| ind_list = [i for i in range(k + 1)] op_list = [Z for i in range(k)] + [s_minus] return qu.ikron(ops=op_list, dims=self._dims, inds=ind_list)
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 test_quevo_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 = eigsys(ham) sim = QuEvo(p0, (l, v)) assert sim._solved else: sim = QuEvo(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_chop_copy(self): a = qu.qu([-1j, 0.1 + 0.2j]) b = qu.chop(a, tol=0.11, inplace=False) assert_allclose(a, qu.qu([-1j, 0.1 + 0.2j])) assert_allclose(b, qu.qu([-1j, 0.2j])) # Sparse a = qu.qu([-1j, 0.1 + 0.2j], sparse=True) b = qu.chop(a, tol=0.11, inplace=False) ao = qu.qu([-1j, 0.1 + 0.2j], sparse=True) bo = qu.qu([-1j, 0.2j], sparse=True) assert ((a != ao).nnz == 0) assert ((b != bo).nnz == 0)
def test_evo_ham(self, ham_rcr_psi, sparse, dop, method, timedep, linop): ham, trc, p0, tm, pm = ham_rcr_psi if dop: if method == 'expm': # XXX: not implemented return p0 = p0 @ p0.H pm = pm @ pm.H if method == 'bad': with raises(ValueError): qu.Evolution(p0, ham, method=method) return ham = qu.qu(ham, sparse=sparse) if linop: import scipy.sparse.linalg as spla ham = spla.aslinearoperator(ham) if timedep: # fake a time dependent ham by making it callable ham_object, ham = ham, (lambda t: ham_object) if linop and (method in ('expm', 'solve')): with raises(TypeError): qu.Evolution(p0, ham, method=method) return if timedep and (method in ('expm', 'solve')): with raises(TypeError): qu.Evolution(p0, ham, method=method) return sim = qu.Evolution(p0, ham, method=method) sim.update_to(tm) assert_allclose(sim.pt, pm, rtol=1e-4, atol=1e-6) assert qu.expec(sim.pt, p0) < 1.0 sim.update_to(trc) assert_allclose(sim.pt, p0, rtol=1e-4, atol=1e-6) assert isinstance(sim.pt, qu.qarray) assert sim.t == trc
def test_quevo_compute_callback(self, qtype, method): ham = ham_heis(2, cyclic=False) p0 = qu(up() & down(), qtype=qtype) def some_quantity(t, pt): return t, logneg(pt) evo = QuEvo(p0, ham, method=method, compute=some_quantity) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(logneg(pt)) ts, lns = zip(*evo.results) assert len(lns) >= len(manual_lns) # check a specific value of logneg at t=0.8 was computed automatically checked = False for t, ln in zip(ts, lns): if abs(t - 0.8) < 1e-12: assert abs(ln - manual_lns[4]) < 1e-12 checked = True assert checked
def jw_annihil_op(self, k, spin): ''' Annihilation Jordan-Wigner qubit operator, acting on site `k` and `spin` sector. (Z_0)x(Z_1)x ...x(Z_k-1)x |0><1|_k ''' spin = {0: 0, 1: 1, 'up': 0, 'down': 1, 'u': 0, 'd': 1}[spin] Z, I = qu.pauli('z'), qu.eye(2) s_minus = qu.qu([[0, 1], [0, 0]]) #|0><1| N = self._Nverts Z_sig = {0: Z & I, 1: I & Z}[spin] s_minus_sig = {0: s_minus & I, 1: I & s_minus}[spin] op_list = [Z_sig for i in range(k)] + [s_minus_sig] ind_list = [i for i in range(k + 1)] return qu.ikron(ops=op_list, dims=self._dims, inds=ind_list)
def jw_creation_op(self, k, spin): ''' Jordan-Wigner transformed creation operator, for site k and `spin` sector (Z_0)x(Z_1)x ...x(Z_k-1)x |1><0|_k ''' spin = {0: 0, 1: 1, 'up': 0, 'down': 1, 'u': 0, 'd': 1}[spin] Z, I = qu.pauli('z'), qu.eye(2) s_plus = qu.qu([[0, 0], [1, 0]]) N = self._Nverts Z_sig = {0: Z & I, 1: I & Z}[spin] s_plus_sig = {0: s_plus & I, 1: I & s_plus}[spin] op_list = [Z_sig for i in range(k)] + [s_plus_sig] ind_list = [i for i in range(k + 1)] return qu.ikron(ops=op_list, dims=self._dims, inds=ind_list)
def test_reshape_sparse(self, qtype, shape, out, format_in, format_out, dtype): import warnings in_ = [[1], [0], [2], [3j]] x = qu.core.sparse_matrix(in_, stype=format_in) with warnings.catch_warnings(): warnings.simplefilter("ignore") y = qu.qu(x, qtype=qtype, stype=format_out, dtype=dtype) assert y.shape == shape assert y.dtype == dtype if format_out is None: format_out = format_in assert y.format == format_out if np.issubdtype(dtype, np.floating): assert_allclose(y.A, np.real(out), atol=1e-12) else: assert_allclose(y.A, out)
def test_evo_multi_compute(self, method, qtype): ham = qu.ham_heis(2, cyclic=False) p0 = qu.qu(qu.up() & qu.down(), qtype=qtype) def some_quantity(t, _): return t def some_other_quantity(_, pt): return qu.logneg(pt) # check that hamiltonian gets accepted without error for all methods def some_other_quantity_accepting_ham(t, pt, H): return qu.logneg(pt) compute = { 't': some_quantity, 'logneg': some_other_quantity, 'logneg_ham': some_other_quantity_accepting_ham } evo = qu.Evolution(p0, ham, method=method, compute=compute) manual_lns = [] for pt in evo.at_times(np.linspace(0, 1, 6)): manual_lns.append(qu.logneg(pt)) ts = evo.results['t'] lns = evo.results['logneg'] lns_ham = evo.results['logneg_ham'] assert len(lns) >= len(manual_lns) # check a specific value of logneg at t=0.8 was computed automatically checked = False for t, ln, ln_ham in zip(ts, lns, lns_ham): if abs(t - 0.8) < 1e-12: assert abs(ln - manual_lns[4]) < 1e-12 # check that accepting hamiltonian didn't mess it up assert ln == ln_ham checked = True assert checked