def test_QobjHerm(): "Qobj Hermicity" N = 10 data = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) q = Qobj(data) assert_equal(q.isherm, False) data = data + data.conj().T q = Qobj(data) assert_(q.isherm) q_a = destroy(5) assert_(not q_a.isherm) q_ad = create(5) assert_(not q_ad.isherm) # test addition of two nonhermitian operators adding up to a hermitian one q_x = q_a + q_ad assert_(q_x.isherm) # isherm use the _isherm cache from q_a + q_ad q_x._isherm = None # reset _isherm cache assert_(q_x.isherm) # recalculate _isherm # test addition of one hermitan and one nonhermitian operator q = q_x + q_a assert_(not q.isherm) q._isherm = None assert_(not q.isherm) # test addition of two hermitan operators q = q_x + q_x assert_(q.isherm) q._isherm = None assert_(q.isherm)
def testScatteringProbability(self): """ Asserts that pi pulse in TLS has P0 ~ 0 and P0+P1+P2 ~ 1 """ w0 = 1.0 * 2 * np.pi gamma = 1.0 sm = np.sqrt(gamma) * destroy(2) pulseArea = np.pi pulseLength = 0.2 / gamma RabiFreq = pulseArea / (2 * pulseLength) psi0 = basis(2, 0) tlist = np.geomspace(gamma, 10 * gamma, 40) - gamma # Define TLS Hamiltonian H0S = w0 * create(2) * destroy(2) H1S1 = lambda t, args: \ RabiFreq * 1j * np.exp(-1j * w0 * t) * (t < pulseLength) H1S2 = lambda t, args: \ RabiFreq * -1j * np.exp(1j * w0 * t) * (t < pulseLength) Htls = [H0S, [sm.dag(), H1S1], [sm, H1S2]] # Run the test P0 = scattering_probability(Htls, psi0, 0, [sm], tlist) P1 = scattering_probability(Htls, psi0, 1, [sm], tlist) P2 = scattering_probability(Htls, psi0, 2, [sm], tlist) assert_(P0 < 1e-3) assert_(np.abs(P0 + P1 + P2 - 1) < 1e-3)
def rand_super(dim=5): H = rand_herm(dim) return propagator( H, np.random.rand(), [create(dim), destroy(dim), jmat(float(dim - 1) / 2.0, 'z')])
def test_sp_bandwidth(): "Sparse: Bandwidth" # Bandwidth test 1 A = create(25) + destroy(25) + qeye(25) band = sp_bandwidth(A.data) assert_equal(band[0], 3) assert_equal(band[1] == band[2] == 1, 1) # Bandwidth test 2 A = np.array([[1, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 0, 1, 0, 1]], dtype=np.int32) A = sp.csr_matrix(A) out1 = sp_bandwidth(A) assert_equal(out1[0], 13) assert_equal(out1[1] == out1[2] == 6, 1) # Bandwidth test 3 perm = reverse_cuthill_mckee(A) B = sp_permute(A, perm, perm) out2 = sp_bandwidth(B) assert_equal(out2[0], 5) assert_equal(out2[1] == out2[2] == 2, 1) # Asymmetric bandwidth test A = destroy(25) + qeye(25) out1 = sp_bandwidth(A.data) assert_equal(out1[0], 2) assert_equal(out1[1], 0) assert_equal(out1[2], 1)
def testScatteringAmplitude(self): """ Asserts that a 2pi pulse in TLS has ~0 amplitude after pulse """ w0 = 1.0 * 2 * np.pi gamma = 1.0 sm = np.sqrt(gamma) * destroy(2) pulseArea = 2 * np.pi pulseLength = 0.2 / gamma RabiFreq = pulseArea / (2 * pulseLength) psi0 = basis(2, 0) T = 50 tlist = np.linspace(0, 1 / gamma, T) # Define TLS Hamiltonian H0S = w0 * create(2) * destroy(2) H1S1 = lambda t, args: \ RabiFreq * 1j * np.exp(-1j * w0 * t) * (t < pulseLength) H1S2 = lambda t, args: \ RabiFreq * -1j * np.exp(1j * w0 * t) * (t < pulseLength) Htls = [H0S, [sm.dag(), H1S1], [sm, H1S2]] # Run the test state = temporal_scattered_state(Htls, psi0, 1, [sm], tlist) basisVec = temporal_basis_vector([[40]], T) amplitude = np.abs((basisVec.dag() * state).full().item()) assert_(amplitude < 1e-3)
def rand_super(N=5, dims=None): """ Returns a randomly drawn superoperator acting on operators acting on N dimensions. Parameters ---------- N : int Square root of the dimension of the superoperator to be returned. dims : list Dimensions of quantum object. Used for specifying tensor structure. Default is dims=[[[N],[N]], [[N],[N]]]. """ if dims is not None: # TODO: check! pass else: dims = [[[N], [N]], [[N], [N]]] H = rand_herm(N) S = propagator( H, np.random.rand(), [create(N), destroy(N), jmat(float(N - 1) / 2.0, 'z')]) S.dims = dims return S
def test_sp_bandwidth(): "Sparse: Bandwidth" # Bandwidth test 1 A = create(25)+destroy(25)+qeye(25) band = sp_bandwidth(A.data) assert_equal(band[0], 3) assert_equal(band[1] == band[2] == 1, 1) # Bandwidth test 2 A = np.array([[1, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 0, 0, 1, 0, 1], [0, 1, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 0, 1, 0, 1]], dtype=np.int32) A = sp.csr_matrix(A) out1 = sp_bandwidth(A) assert_equal(out1[0], 13) assert_equal(out1[1] == out1[2] == 6, 1) # Bandwidth test 3 perm = reverse_cuthill_mckee(A) B = sp_permute(A, perm, perm) out2 = sp_bandwidth(B) assert_equal(out2[0], 5) assert_equal(out2[1] == out2[2] == 2, 1) # Asymmetric bandwidth test A = destroy(25)+qeye(25) out1 = sp_bandwidth(A.data) assert_equal(out1[0], 2) assert_equal(out1[1], 0) assert_equal(out1[2], 1)
def test_QobjHerm(): "Qobj Hermicity" N = 10 data = np.random.random((N, N)) + 1j * np.random.random( (N, N)) - (0.5 + 0.5j) q = Qobj(data) assert_equal(q.isherm, False) data = data + data.conj().T q = Qobj(data) assert_(q.isherm) q_a = destroy(5) assert_(not q_a.isherm) q_ad = create(5) assert_(not q_ad.isherm) # test addition of two nonhermitian operators adding up to a hermitian one q_x = q_a + q_ad assert_(q_x.isherm) # isherm use the _isherm cache from q_a + q_ad q_x._isherm = None # reset _isherm cache assert_(q_x.isherm) # recalculate _isherm # test addition of one hermitan and one nonhermitian operator q = q_x + q_a assert_(not q.isherm) q._isherm = None assert_(not q.isherm) # test addition of two hermitan operators q = q_x + q_x assert_(q.isherm) q._isherm = None assert_(q.isherm)
def test_SuperChoiSuper(self): """ Superoperator: Converting superoperator to Choi matrix and back. """ h_5 = rand_herm(5) superoperator = propagator(h_5, scipy.rand(), [create(5), destroy(5), jmat(2, 'z')]) choi_matrix = super_to_choi(superoperator) test_supe = choi_to_super(choi_matrix) assert_((test_supe - superoperator).norm() < 1e-12)
def test_standard(self): base = _random_not_singular(10) assert not Qobj(base).isherm assert Qobj(base + base.conj().T).isherm q_a = destroy(5) assert not q_a.isherm q_ad = create(5) assert not q_ad.isherm
def test_SuperChoiSuper(self): """ Superoperator: Converting superoperator to Choi matrix and back. """ h_5 = rand_herm(5) superoperator = propagator( h_5, scipy.rand(), [create(5), destroy(5), jmat(2, 'z')]) choi_matrix = super_to_choi(superoperator) test_supe = choi_to_super(choi_matrix) assert_((test_supe - superoperator).norm() < 1e-12)
def test_ChoiKrausChoi(self): """ Superoperator: Converting superoperator to Choi matrix and back. """ h_5 = rand_herm(5) superoperator = propagator(h_5, scipy.rand(), [create(5), destroy(5), jmat(2, 'z')]) choi_matrix = super_to_choi(superoperator) kraus_ops = choi_to_kraus(choi_matrix) test_choi = kraus_to_choi(kraus_ops) assert_((test_choi - choi_matrix).norm() < 1e-12)
def test_ChoiKrausChoi(self): """ Superoperator: Converting superoperator to Choi matrix and back. """ h_5 = rand_herm(5) superoperator = propagator( h_5, scipy.rand(), [create(5), destroy(5), jmat(2, 'z')]) choi_matrix = super_to_choi(superoperator) kraus_ops = choi_to_kraus(choi_matrix) test_choi = kraus_to_choi(kraus_ops) assert_((test_choi - choi_matrix).norm() < 1e-12)
def test_addition(self): q_a, q_ad = destroy(5), create(5) # test addition of two nonhermitian operators adding up to be hermitian q_x = q_a + q_ad assert_hermicity(q_x, True) # test addition of one hermitan and one nonhermitian operator q = q_x + q_a assert_hermicity(q, False) # test addition of two hermitan operators q = q_x + q_x assert_hermicity(q, True)
def test_QobjHerm(): "Qobj Hermicity" N = 10 data = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) q = Qobj(data) assert_equal(q.isherm, False) data = data + data.conj().T q = Qobj(data) assert_(q.isherm) q_a = destroy(5) assert_(not q_a.isherm) q_ad = create(5) assert_(not q_ad.isherm) # test addition of two nonhermitian operators adding up to a hermitian one q_x = q_a + q_ad assert_hermicity(q_x, True) # test addition of one hermitan and one nonhermitian operator q = q_x + q_a assert_hermicity(q, False) # test addition of two hermitan operators q = q_x + q_x assert_hermicity(q, True) # Test multiplication of two Hermitian operators. # This results in a skew-Hermitian operator, so # we're checking here that __mul__ doesn't set wrong # metadata. q = sigmax() * sigmay() assert_hermicity(q, False, "Expected iZ = X * Y to be skew-Hermitian.") # Similarly, we need to check that -Z = X * iY is correctly # identified as Hermitian. q = sigmax() * (1j * sigmay()) assert_hermicity(q, True, "Expected -Z = X * iY to be Hermitian.")
def rand_super(N=5, dims=None): """ Returns a randomly drawn superoperator acting on operators acting on N dimensions. Parameters ---------- N : int Square root of the dimension of the superoperator to be returned. dims : list Dimensions of quantum object. Used for specifying tensor structure. Default is dims=[[[N],[N]], [[N],[N]]]. """ if dims is not None: # TODO: check! pass else: dims = [[[N], [N]], [[N], [N]]] H = rand_herm(N) S = propagator(H, np.random.rand(), [create(N), destroy(N), jmat(float(N - 1) / 2.0, "z")]) S.dims = dims return S
class TestSuperopReps: """ A test class for the QuTiP function for applying superoperators to subsystems. """ def test_SuperChoiSuper(self, superoperator): """ Superoperator: Converting superoperator to Choi matrix and back. """ choi_matrix = to_choi(superoperator) test_supe = to_super(choi_matrix) # Assert both that the result is close to expected, and has the right # type. assert (test_supe - superoperator).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert test_supe.type == "super" and test_supe.superrep == "super" @pytest.mark.parametrize('dimension', [2, 4]) def test_SuperChoiChiSuper(self, dimension): """ Superoperator: Converting two-qubit superoperator through Choi and chi representations goes back to right superoperator. """ superoperator = super_tensor( rand_super(dimension), rand_super(dimension), ) choi_matrix = to_choi(superoperator) chi_matrix = to_chi(choi_matrix) test_supe = to_super(chi_matrix) # Assert both that the result is close to expected, and has the right # type. assert (test_supe - superoperator).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert chi_matrix.type == "super" and chi_matrix.superrep == "chi" assert test_supe.type == "super" and test_supe.superrep == "super" def test_ChoiKrausChoi(self, superoperator): """ Superoperator: Convert superoperator to Choi matrix and back. """ choi_matrix = to_choi(superoperator) kraus_ops = to_kraus(choi_matrix) test_choi = kraus_to_choi(kraus_ops) # Assert both that the result is close to expected, and has the right # type. assert (test_choi - choi_matrix).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert test_choi.type == "super" and test_choi.superrep == "choi" def test_NonSquareKrausSuperChoi(self): """ Superoperator: Convert non-square Kraus operator to Super + Choi matrix and back. """ zero = asarray([[1], [0]], dtype=complex) one = asarray([[0], [1]], dtype=complex) zero_log = kron(kron(zero, zero), zero) one_log = kron(kron(one, one), one) # non-square Kraus operator (isometry) kraus = Qobj(zero_log @ zero.T + one_log @ one.T) super = sprepost(kraus, kraus.dag()) choi = to_choi(super) op1 = to_kraus(super) op2 = to_kraus(choi) op3 = to_super(choi) assert choi.type == "super" and choi.superrep == "choi" assert super.type == "super" and super.superrep == "super" assert (op1[0] - kraus).norm() < tol assert (op2[0] - kraus).norm() < tol assert (op3 - super).norm() < tol def test_NeglectSmallKraus(self): """ Superoperator: Convert Kraus to Choi matrix and back. Neglect tiny Kraus operators. """ zero = asarray([[1], [0]], dtype=complex) one = asarray([[0], [1]], dtype=complex) zero_log = kron(kron(zero, zero), zero) one_log = kron(kron(one, one), one) # non-square Kraus operator (isometry) kraus = Qobj(zero_log @ zero.T + one_log @ one.T) super = sprepost(kraus, kraus.dag()) # 1 non-zero Kraus operator the rest are zero sixteen_kraus_ops = to_kraus(super, tol=0.0) # default is tol=1e-9 one_kraus_op = to_kraus(super) assert len(sixteen_kraus_ops) == 16 and len(one_kraus_op) == 1 assert (one_kraus_op[0] - kraus).norm() < tol def test_SuperPreservesSelf(self, superoperator): """ Superoperator: to_super(q) returns q if q is already a supermatrix. """ assert superoperator is to_super(superoperator) def test_ChoiPreservesSelf(self, superoperator): """ Superoperator: to_choi(q) returns q if q is already Choi. """ choi = to_choi(superoperator) assert choi is to_choi(choi) def test_random_iscptp(self, superoperator): """ Superoperator: Randomly generated superoperators are correctly reported as CPTP and HP. """ assert superoperator.iscptp assert superoperator.ishp # Conjugation by a creation operator a = create(2).dag() S = sprepost(a, a.dag()) # A single off-diagonal element S_ = sprepost(a, a) # Check that a linear combination of bipartite unitaries is CPTP and HP. S_U = (to_super(tensor(sigmax(), identity(2))) + to_super(tensor(identity(2), sigmay()))) / 2 # The partial transpose map, whose Choi matrix is SWAP ptr_swap = Qobj(swap(), type='super', superrep='choi') # Subnormalized maps (representing erasure channels, for instance) subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') @pytest.mark.parametrize(['qobj', 'shouldhp', 'shouldcp', 'shouldtp'], [ pytest.param(S, True, True, False, id="conjugatio by create op"), pytest.param(S_, False, False, False, id="single off-diag"), pytest.param(identity(2), True, True, True, id="Identity"), pytest.param(sigmax(), True, True, True, id="Pauli X"), pytest.param( tensor(sigmax(), identity(2)), True, True, True, id="bipartite system", ), pytest.param( S_U, True, True, True, id="linear combination of bip. unitaries", ), pytest.param(ptr_swap, True, False, True, id="partial transpose map"), pytest.param(subnorm_map, True, True, False, id="subnorm map"), pytest.param(basis(2), False, False, False, id="not an operator"), ]) def test_known_iscptp(self, qobj, shouldhp, shouldcp, shouldtp): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ assert qobj.ishp == shouldhp assert qobj.iscp == shouldcp assert qobj.istp == shouldtp assert qobj.iscptp == (shouldcp and shouldtp) def test_choi_tr(self, dimension): """ Superoperator: Trace returned by to_choi matches docstring. """ assert abs(to_choi(identity(dimension)).tr() - dimension) <= tol def test_stinespring_cp(self, dimension): """ Stinespring: A and B match for CP maps. """ superop = rand_super_bcsz(dimension) A, B = to_stinespring(superop) assert norm(A - B) < tol @pytest.mark.repeat(3) def test_stinespring_agrees(self, dimension): """ Stinespring: Partial Tr over pair agrees w/ supermatrix. """ map = rand_super_bcsz(dimension) state = rand_dm_ginibre(dimension) S = to_super(map) A, B = to_stinespring(map) q1 = vector_to_operator(S * operator_to_vector(state)) # FIXME: problem if Kraus index is implicitly # ptraced! q2 = (A * state * B.dag()).ptrace((0, )) assert (q1 - q2).norm('tr') <= tol def test_stinespring_dims(self, dimension): """ Stinespring: Check that dims of channels are preserved. """ chan = super_tensor(to_super(sigmax()), to_super(qeye(dimension))) A, B = to_stinespring(chan) assert A.dims == [[2, dimension, 1], [2, dimension]] assert B.dims == [[2, dimension, 1], [2, dimension]] @pytest.mark.parametrize('dimension', [2, 4, 8]) def test_chi_choi_roundtrip(self, dimension): superop = rand_super_bcsz(dimension) superop = to_chi(superop) rt_superop = to_chi(to_choi(superop)) dif = norm(rt_superop - superop) assert dif == pytest.approx(0, abs=1e-7) assert rt_superop.type == superop.type assert rt_superop.dims == superop.dims chi_sigmax = [[0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] chi_diag2 = [[4, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] rotX_pi_4 = (-1j * sigmax() * pi / 4).expm() chi_rotX_pi_4 = [[2, 2j, 0, 0], [-2j, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] @pytest.mark.parametrize(['superop', 'chi_expected'], [ pytest.param(sigmax(), chi_sigmax), pytest.param(to_super(sigmax()), chi_sigmax), pytest.param(qeye(2), chi_diag2), pytest.param(rotX_pi_4, chi_rotX_pi_4) ]) def test_chi_known(self, superop, chi_expected): """ Superoperator: Chi-matrix for known cases is correct. """ chi_actual = to_chi(superop) chiq = Qobj( chi_expected, dims=[[[2], [2]], [[2], [2]]], superrep='chi', ) assert (chi_actual - chiq).norm() < tol
def test_known_iscptp(self): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ def case(qobj, shouldhp, shouldcp, shouldtp): hp = qobj.ishp cp = qobj.iscp tp = qobj.istp cptp = qobj.iscptp shouldcptp = shouldcp and shouldtp if (hp == shouldhp and cp == shouldcp and tp == shouldtp and cptp == shouldcptp): return fails = [] if hp != shouldhp: fails.append(("ishp", shouldhp, hp)) if tp != shouldtp: fails.append(("istp", shouldtp, tp)) if cp != shouldcp: fails.append(("iscp", shouldcp, cp)) if cptp != shouldcptp: fails.append(("iscptp", shouldcptp, cptp)) raise AssertionError("Expected {}.".format(" and ".join([ "{} == {} (got {})".format(fail, expected, got) for fail, expected, got in fails ]))) # Conjugation by a creation operator should # have be CP (and hence HP), but not TP. a = create(2).dag() S = sprepost(a, a.dag()) case(S, True, True, False) # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) case(S, False, False, False) # Check that unitaries are CPTP and HP. case(identity(2), True, True, True) case(sigmax(), True, True, True) # Check that unitaries on bipartite systems are CPTP and HP. case(tensor(sigmax(), identity(2)), True, True, True) # Check that a linear combination of bipartitie unitaries is CPTP and HP. S = (to_super(tensor(sigmax(), identity(2))) + to_super(tensor(identity(2), sigmay()))) / 2 case(S, True, True, True) # The partial transpose map, whose Choi matrix is SWAP, is TP # and HP but not CP (one negative eigenvalue). W = Qobj(swap(), type='super', superrep='choi') case(W, True, False, True) # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') case(subnorm_map, True, True, False) # Check that things which aren't even operators aren't identified as # CPTP. case(basis(2), False, False, False)
def rand_super(dim=5): H = rand_herm(dim) return propagator(H, np.random.rand(), [ create(dim), destroy(dim), jmat(float(dim - 1) / 2.0, 'z') ])
def test_known_iscptp(self): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ def case(qobj, shouldhp, shouldcp, shouldtp): hp = qobj.ishp cp = qobj.iscp tp = qobj.istp cptp = qobj.iscptp shouldcptp = shouldcp and shouldtp if ( hp == shouldhp and cp == shouldcp and tp == shouldtp and cptp == shouldcptp ): return fails = [] if hp != shouldhp: fails.append(("ishp", shouldhp, hp)) if tp != shouldtp: fails.append(("istp", shouldtp, tp)) if cp != shouldcp: fails.append(("iscp", shouldcp, cp)) if cptp != shouldcptp: fails.append(("iscptp", shouldcptp, cptp)) raise AssertionError("Expected {}.".format(" and ".join([ "{} == {} (got {})".format(fail, expected, got) for fail, expected, got in fails ]))) # Conjugation by a creation operator should # have be CP (and hence HP), but not TP. a = create(2).dag() S = sprepost(a, a.dag()) yield case, S, True, True, False # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) yield case, S, False, False, False # Check that unitaries are CPTP and HP. yield case, identity(2), True, True, True yield case, sigmax(), True, True, True # The partial transpose map, whose Choi matrix is SWAP, is TP # and HP but not CP (one negative eigenvalue). W = Qobj(swap(), type='super', superrep='choi') yield case, W, True, False, True # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') yield case, subnorm_map, True, True, False # Check that things which aren't even operators aren't identified as # CPTP. yield case, basis(2), False, False, False
def rand_super(self): h_5 = rand_herm(5) return propagator( h_5, scipy.rand(), [create(5), destroy(5), jmat(2, 'z')])
def rand_super(): h_5 = rand_herm(5) return propagator(h_5, scipy.rand(), [ create(5), destroy(5), jmat(2, 'z') ])