def test_liouville_to_choi(self): """Test converting Liouville superops to choi matrices.""" for d in rng.integers(2, 9, (15, )): # unitary channel U = testutil.rand_unit(d, rng.integers(1, 8)).squeeze() n = np.log2(d) if n % 1 == 0: basis = ff.Basis.pauli(int(n)) else: basis = ff.Basis.ggm(d) U_sup = superoperator.liouville_representation(U, basis) choi = superoperator.liouville_to_choi(U_sup, basis).view(ff.Basis) self.assertTrue(choi.isherm) self.assertArrayAlmostEqual(np.einsum('...ii', choi), d) pulse = testutil.rand_pulse_sequence(d, 1) omega = ff.util.get_sample_frequencies(pulse) S = 1 / abs(omega)**2 U_sup = ff.error_transfer_matrix(pulse, S, omega) choi = superoperator.liouville_to_choi(U_sup, basis).view(ff.Basis) self.assertTrue(choi.isherm) self.assertAlmostEqual(np.einsum('ii', choi), d)
def test_get_states_from_prop(self): P = testutil.rand_unit(2, 10) Q = np.empty((11, 2, 2), dtype=complex) Q[0] = np.identity(2) for i in range(10): Q[i + 1] = P[i] @ Q[i] psi0 = qutip.rand_ket(2) states_piecewise = plotting.get_states_from_prop(P, psi0, 'piecewise') states_total = plotting.get_states_from_prop(Q[1:], psi0, 'total') self.assertArrayAlmostEqual(states_piecewise, states_total)
def test_dot_HS(self): U, V = rng.randint(0, 100, (2, 2, 2)) S = util.dot_HS(U, V) T = util.dot_HS(U, V, eps=0) self.assertArrayEqual(S, T) for d in rng.randint(2, 10, (5, )): U, V = testutil.rand_herm(d, 2) self.assertArrayAlmostEqual(util.dot_HS(U, V), (U.conj().T @ V).trace()) U = testutil.rand_unit(d).squeeze() self.assertEqual(util.dot_HS(U, U), d) self.assertEqual(util.dot_HS(U, U + 1e-14, eps=1e-10), d)
def test_liouville_is_CP(self): def partial_transpose(A): d = A.shape[-1] sqd = int(np.sqrt(d)) return A.reshape(-1, sqd, sqd, sqd, sqd).swapaxes(-1, -3).reshape(A.shape) # Partial transpose map should be non-CP basis = ff.Basis.pauli(2) Phi = ff.basis.expand(partial_transpose(basis), basis).T CP = superoperator.liouville_is_CP(Phi, basis) self.assertFalse(CP) for d in rng.integers(2, 9, (15, )): # unitary channel U = testutil.rand_unit(d, rng.integers(1, 8)).squeeze() n = np.log2(d) if n % 1 == 0: basis = ff.Basis.pauli(int(n)) else: basis = ff.Basis.ggm(d) U_sup = superoperator.liouville_representation(U, basis) CP, (D, V) = superoperator.liouville_is_CP(U_sup, basis, True) _CP = superoperator.liouville_is_CP(U_sup, basis, False) self.assertArrayEqual(CP, _CP) self.assertTrue(np.all(CP)) if U_sup.ndim == 2: self.assertIsInstance(CP, (bool, np.bool8)) else: self.assertEqual(CP.shape[0], U_sup.shape[0]) # Only one nonzero eigenvalue self.assertArrayAlmostEqual(D[..., :-1], 0, atol=basis._atol) pulse = testutil.rand_pulse_sequence(d, 1) omega = ff.util.get_sample_frequencies(pulse) S = 1 / abs(omega)**2 U_sup = ff.error_transfer_matrix(pulse, S, omega) CP = superoperator.liouville_is_CP(U_sup, pulse.basis) self.assertTrue(np.all(CP)) self.assertIsInstance(CP, (bool, np.bool8))
def test_liouville_representation(self): """Test the calculation of the transfer matrix""" dd = np.arange(2, 18, 4) for d in dd: # Works with different bases if d == 4: basis = ff.Basis.pauli(2) else: basis = ff.Basis.ggm(d) U = testutil.rand_unit(d, 2) # Works on matrices and arrays of matrices U_liouville = superoperator.liouville_representation(U[0], basis) U_liouville = superoperator.liouville_representation(U, basis) # should have dimension d^2 x d^2 self.assertEqual(U_liouville.shape, (U.shape[0], d**2, d**2)) # Real self.assertTrue(np.isreal(U_liouville).all()) # Hermitian for unitary input self.assertArrayAlmostEqual( U_liouville.swapaxes(-1, -2) @ U_liouville, np.tile(np.eye(d**2), (U.shape[0], 1, 1)), atol=5 * np.finfo(float).eps * d**2) if d == 2: U_liouville = superoperator.liouville_representation( ff.util.paulis[1:], basis) self.assertArrayAlmostEqual(U_liouville[0], np.diag([1, 1, -1, -1]), atol=basis._atol) self.assertArrayAlmostEqual(U_liouville[1], np.diag([1, -1, 1, -1]), atol=basis._atol) self.assertArrayAlmostEqual(U_liouville[2], np.diag([1, -1, -1, 1]), atol=basis._atol)