def test_liouville_to_choi(self): """Test converting Liouville superops to choi matrices.""" for d in rng.randint(2, 9, (15, )): # unitary channel U = testutil.rand_unit(d, rng.randint(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_basis_generation_from_partial_pauli(self): """"Generate complete basis from partial elements of a Pauli basis""" # Do 100 test runs with random elements from a Pauli basis in (2 ... 8) # dimensions for _ in range(50): n = rng.randint(1, 4) d = 2**n b = ff.Basis.pauli(n) inds = [i for i in range(d**2)] tup = tuple( inds.pop(rng.randint(0, len(inds))) for _ in range(rng.randint(1, d**2))) elems = b[tup, ...] basis = ff.Basis(elems) self.assertTrue(basis.isorthonorm) self.assertTrue(basis.isherm) self.assertTrue(basis.istraceless) self.assertTrue(basis.iscomplete) self.assertTrue(all(elem in basis for elem in elems)) with self.assertWarns(UserWarning): b = [basis[0], 1j * basis[1]] ff.Basis(b) with self.assertRaises(ValueError): b = [basis[0], basis[0] + basis[1]] ff.Basis(b)
def test_multi_qubit_error_transfer_matrix(self): """Test the calculation of the multi-qubit transfer matrix""" n_cops = 4 n_nops = 2 for d, n_dt in zip(rng.randint(3, 9, 10), rng.randint(1, 11, 10)): f, n = np.modf(np.log2(d)) btype = 'Pauli' if f == 0.0 else 'GGM' pulse = testutil.rand_pulse_sequence(d, n_dt, n_cops, n_nops, btype) omega = util.get_sample_frequencies(pulse, n_samples=51) # Assert fidelity is same as computed by infidelity() S = 1e-8 / omega**2 U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = 1 - np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(Up, U) self.assertArrayAlmostEqual(I_transfer, I_fidelity.sum(), atol=1e-4) S = np.outer(1e-7 * (np.arange(n_nops) + 1), 400 / (omega**2 + 400)) U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = 1 - np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(Up, U) self.assertArrayAlmostEqual(I_transfer, I_fidelity.sum(), atol=1e-4) S = np.tile(1e-8 / abs(omega)**2, (n_nops, n_nops, 1)).astype(complex) S[np.triu_indices(n_nops, 1)].imag = 1e-10 * omega S[np.tril_indices(n_nops, -1)].imag = \ - S[np.triu_indices(n_nops, 1)].imag U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = 1 - np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(Up, U) self.assertArrayAlmostEqual(I_transfer, I_fidelity.sum(), atol=1e-4)
def test_basis_properties(self): """Basis orthonormal and of correct dimensions""" d = rng.randint(2, 17) n = rng.randint(1, 5) ggm_basis = ff.Basis.ggm(d) pauli_basis = ff.Basis.pauli(n) custom_basis = ff.Basis(testutil.rand_herm(d), traceless=False) btypes = ('Pauli', 'GGM', 'Custom') bases = (pauli_basis, ggm_basis, custom_basis) for btype, base in zip(btypes, bases): base.tidyup(eps_scale=0) self.assertTrue(base == base) self.assertFalse(base == ff.Basis.ggm(d + 1)) self.assertEqual(btype, base.btype) if not btype == 'Pauli': self.assertEqual(d, base.d) # Check if __contains__ works as expected self.assertTrue(base[rng.randint(0, d**2)] in base) else: self.assertEqual(2**n, base.d) # Check if __contains__ works as expected self.assertTrue(base[rng.randint(0, (2**n)**2)] in base) # Check if all elements of each basis are orthonormal and hermitian self.assertArrayEqual(base.T, base.view(np.ndarray).swapaxes(-1, -2)) self.assertTrue(base.isorthonorm) self.assertTrue(base.isherm) # Check if basis spans the whole space and all elems are traceless if not btype == 'Custom': self.assertTrue(base.istraceless) else: self.assertFalse(base.istraceless) self.assertTrue(base.iscomplete) # Check sparse representation self.assertArrayEqual(base.sparse.todense(), base) # Test sparse cache self.assertArrayEqual(base.sparse.todense(), base) if base.d < 8: # Test very resource intense ref = np.einsum('iab,jbc,kcd,lda', *(base, ) * 4) self.assertArrayAlmostEqual(base.four_element_traces.todense(), ref, atol=1e-16) # Test setter base._four_element_traces = None base.four_element_traces = ref self.assertArrayEqual(base.four_element_traces, ref) base._print_checks() basis = ff.util.paulis[1].view(ff.Basis) self.assertTrue(basis.isorthonorm) self.assertArrayEqual(basis.T, basis.view(np.ndarray).T)
def test_tensor_transpose(self): # Test basic functionality paulis = np.array(util.paulis) I, X, Y, Z = paulis arr = util.tensor(I, X, Y, Z) arr_dims = [[2] * 4] * 2 order = np.arange(4) for _ in range(20): order = rng.permutation(order) r = util.tensor_transpose(arr, order, arr_dims) self.assertArrayAlmostEqual(r, util.tensor(*paulis[order])) # Check exceptions with self.assertRaises(ValueError): # wrong arr_dims (too few dims) r = util.tensor_transpose(arr, order, [[2] * 3] * 2) with self.assertRaises(ValueError): # wrong arr_dims (too few dims) r = util.tensor_transpose(arr, order, [[2] * 4] * 1) with self.assertRaises(ValueError): # wrong arr_dims (dims too large) r = util.tensor_transpose(arr, order, [[3] * 4] * 2) with self.assertRaises(ValueError): # wrong order (too few axes) r = util.tensor_transpose(arr, (0, 1, 2), arr_dims) with self.assertRaises(ValueError): # wrong order (index 4 too large) r = util.tensor_transpose(arr, (1, 2, 3, 4), arr_dims) with self.assertRaises(ValueError): # wrong order (not unique axes) r = util.tensor_transpose(arr, (1, 1, 1, 1), arr_dims) with self.assertRaises(TypeError): # wrong order (floats instead of ints) r = util.tensor_transpose(arr, (0., 1., 2., 3.), arr_dims) # random tests for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10), rng.randint(3, 6, 10), rng.randint(1, 11, 10)): arrs = rng.standard_normal((n_args, n_broadcast, *[2] * rank)) order = rng.permutation(n_args) arr_dims = [[2] * n_args] * rank r = util.tensor_transpose(util.tensor(*arrs, rank=rank), order=order, arr_dims=arr_dims, rank=rank) self.assertArrayAlmostEqual(r, util.tensor(*arrs[order], rank=rank))
def test_oper_equiv(self): with self.assertRaises(ValueError): util.oper_equiv(rng.standard_normal((2, 2)), rng.standard_normal((3, 3))) for d in rng.randint(2, 10, (5, )): psi = rng.standard_normal((d, 1)) + 1j * rng.standard_normal( (d, 1)) # Also test broadcasting U = testutil.rand_herm(d, rng.randint(1, 11)).squeeze() phase = rng.standard_normal() result = util.oper_equiv(psi, psi * np.exp(1j * phase)) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(psi * np.exp(1j * phase), psi) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], -phase, places=5) psi /= np.linalg.norm(psi, ord=2) result = util.oper_equiv(psi, psi * np.exp(1j * phase), normalized=True, eps=1e-13) self.assertTrue(result[0]) self.assertArrayAlmostEqual(result[1], phase, atol=1e-5) result = util.oper_equiv(psi, psi + 1) self.assertFalse(result[0]) result = util.oper_equiv(U, U * np.exp(1j * phase)) self.assertTrue(np.all(result[0])) self.assertArrayAlmostEqual(result[1], phase, atol=1e-5) result = util.oper_equiv(U * np.exp(1j * phase), U) self.assertTrue(np.all(result[0])) self.assertArrayAlmostEqual(result[1], -phase, atol=1e-5) norm = np.sqrt(util.dot_HS(U, U)) norm = norm[:, None, None] if U.ndim == 3 else norm U /= norm # TIP: In numpy 1.18 we could just do: # U /= np.expand_dims(np.sqrt(util.dot_HS(U, U)), axis=(-1, -2)) result = util.oper_equiv(U, U * np.exp(1j * phase), normalized=True, eps=1e-10) self.assertTrue(np.all(result[0])) self.assertArrayAlmostEqual(result[1], phase) result = util.oper_equiv(U, U + 1) self.assertFalse(np.all(result[0]))
def test_tensor(self): shapes = [(1, 2, 3, 4, 5), (5, 4, 3, 2, 1)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) with self.assertRaises(ValueError): util.tensor(A, B) shapes = [(3, 2, 1), (3, 4, 2)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) with self.assertRaises(ValueError): util.tensor(A, B, rank=1) self.assertEqual(util.tensor(A, B, rank=2).shape, (3, 8, 2)) self.assertEqual(util.tensor(A, B, rank=3).shape, (9, 8, 2)) shapes = [(10, 1, 3, 2), (10, 1, 2, 3)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) self.assertEqual(util.tensor(A, B).shape, (10, 1, 6, 6)) shapes = [(3, 5, 4, 4), (3, 5, 4, 4)] A = rng.standard_normal(shapes[0]) B = rng.standard_normal(shapes[1]) self.assertEqual(util.tensor(A, B).shape, (3, 5, 16, 16)) d = rng.randint(2, 9) eye = np.eye(d) for i in range(d): for j in range(d): A, B = eye[i:i + 1, :], eye[:, j:j + 1] self.assertArrayEqual(util.tensor(A, B, rank=1), np.kron(A, B)) i, j = rng.randint(0, 4, (2, )) A, B = util.paulis[i], util.paulis[j] self.assertArrayEqual(util.tensor(A, B), np.kron(A, B)) args = [ rng.standard_normal((4, 1, 2)), rng.standard_normal((3, 2)), rng.standard_normal((4, 3, 5)) ] self.assertEqual(util.tensor(*args, rank=1).shape, (4, 3, 20)) self.assertEqual(util.tensor(*args, rank=2).shape, (4, 9, 20)) self.assertEqual(util.tensor(*args, rank=3).shape, (16, 9, 20)) args = [rng.standard_normal((2, 3, 4)), rng.standard_normal((4, 3))] with self.assertRaises(ValueError) as err: util.tensor(*args, rank=1) msg = ('Incompatible shapes (2, 3, 4) and (4, 3) for tensor ' + 'product of rank 1.') self.assertEqual(msg, str(err.exception))
def test_multi_qubit_error_transfer_matrix(self): """Test the calculation of the multi-qubit transfer matrix""" n_cops = 4 n_nops = 2 for d, n_dt in zip(rng.randint(3, 9, 10), rng.randint(1, 11, 10)): f, n = np.modf(np.log2(d)) btype = 'Pauli' if f == 0.0 else 'GGM' pulse = testutil.rand_pulse_sequence(d, n_dt, n_cops, n_nops, btype) omega = ff.util.get_sample_frequencies(pulse, n_samples=51) # Assert fidelity is same as computed by infidelity() S = 1e-2 / omega**2 U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) self.assertArrayAlmostEqual(Up, U) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(I_transfer, I_fidelity) S = np.outer(1e-2 * (np.arange(n_nops) + 1), 400 / (omega**2 + 400)) U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) self.assertArrayAlmostEqual(Up, U) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(I_transfer, I_fidelity) S = np.einsum('i,j,o->ijo', 1e-2 * (np.arange(n_nops) + 1), 1e-2 * (np.arange(n_nops) + 1), 400 / (omega**2 + 400)) U = ff.error_transfer_matrix(pulse, S, omega) # Calculate U in loop Up = ff.error_transfer_matrix(pulse, S, omega, memory_parsimonious=True) self.assertArrayAlmostEqual(Up, U) I_fidelity = ff.infidelity(pulse, S, omega) I_transfer = np.einsum('...ii', U) / d**2 self.assertArrayAlmostEqual(I_transfer, I_fidelity)
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_cCP(self): for d in rng.randint(2, 9, (15, )): # (anti-) Hermitian generator, should always be cCP H = 1j * testutil.rand_herm(d, rng.randint(1, 8)).squeeze() n = np.log2(d) if n % 1 == 0: basis = ff.Basis.pauli(int(n)) else: basis = ff.Basis.ggm(d) H_sup = (np.einsum('iab,...bc,jca', basis, H, basis, optimize=['einsum_path', (0, 1), (0, 1)]) - np.einsum('iab,jbc,...ca', basis, basis, H, optimize=['einsum_path', (0, 2), (0, 1)])) cCP, (D, V) = superoperator.liouville_is_cCP(H_sup, basis, True) _cCP = superoperator.liouville_is_cCP(H_sup, basis, False) self.assertArrayEqual(cCP, _cCP) self.assertTrue(np.all(cCP)) if H_sup.ndim == 2: self.assertIsInstance(cCP, (bool, np.bool8)) else: self.assertEqual(cCP.shape[0], H_sup.shape[0]) self.assertArrayAlmostEqual(D, 0, atol=1e-14) self.assertTrue( ff.util.oper_equiv(V, np.eye(d**2)[None, :, :], normalized=True)) pulse = testutil.rand_pulse_sequence(d, 1) omega = ff.util.get_sample_frequencies(pulse) S = 1 / abs(omega)**2 K_sup = ff.numeric.calculate_cumulant_function(pulse, S, omega) cCP = superoperator.liouville_is_cCP(K_sup, pulse.basis, False, atol=1e-13) self.assertTrue(np.all(cCP)) if K_sup.ndim == 2: self.assertIsInstance(cCP, (bool, np.bool8)) else: self.assertEqual(cCP.shape[0], K_sup.shape[0])
def test_basis_expansion_and_normalization(self): """Correct expansion of operators and normalization of bases""" for _ in range(10): d = rng.randint(2, 16) ggm_basis = ff.Basis.ggm(d) basis = ff.Basis(np.einsum('i,ijk->ijk', rng.standard_normal(d**2), ggm_basis), skip_check=True) M = rng.standard_normal((d, d)) + 1j * rng.standard_normal((d, d)) M -= np.trace(M) / d coeffs = ff.basis.expand(M, basis, normalized=False) self.assertArrayAlmostEqual(M, np.einsum('i,ijk', coeffs, basis)) self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis), ff.basis.ggm_expand(M), atol=1e-14) self.assertArrayAlmostEqual(ff.basis.ggm_expand(M), ff.basis.ggm_expand(M, traceless=True), atol=1e-14) n = rng.randint(1, 50) M = (rng.standard_normal((n, d, d)) + 1j * rng.standard_normal( (n, d, d))) coeffs = ff.basis.expand(M, basis, normalized=False) self.assertArrayAlmostEqual( M, np.einsum('li,ijk->ljk', coeffs, basis)) self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis), ff.basis.ggm_expand(M), atol=1e-14) # Argument to ggm_expand not square in last two dimensions with self.assertRaises(ValueError): ff.basis.ggm_expand(basis[..., 0]) self.assertTrue(ff.basis.normalize(basis).isorthonorm) # Basis method and function should give the same normalized = ff.basis.normalize(basis) basis.normalize() self.assertEqual(normalized, basis) # normalize single element elem = basis[1] normalized = ff.basis.normalize(elem) elem.normalize() self.assertEqual(normalized, elem) # Not matrix or sequence of matrices with self.assertRaises(ValueError): ff.basis.normalize(basis[0, 0])
def test_plot_pulse_correlation_filter_function(self): omega = np.linspace(-1, 1, 50) concatenated_simple_pulse = ff.concatenate( (simple_pulse, simple_pulse), calc_pulse_correlation_FF=True, omega=omega) concatenated_complicated_pulse = ff.concatenate( (complicated_pulse, complicated_pulse), calc_pulse_correlation_FF=True, omega=omega) # Exception if not pulse correl. FF is cached with self.assertRaises(ff.util.CalculationError): plotting.plot_pulse_correlation_filter_function(simple_pulse) # Call with default args fig, ax, leg = plotting.plot_pulse_correlation_filter_function( concatenated_simple_pulse) # Non-default args n_oper_identifiers = sample( complicated_pulse.n_oper_identifiers.tolist(), rng.randint(2, 4)) fig, ax = plt.subplots() omega = np.linspace(-10, 10, 50) fig, ax, leg = plotting.plot_pulse_correlation_filter_function( concatenated_complicated_pulse, omega=omega, n_oper_identifiers=n_oper_identifiers, fig=fig, omega_in_units_of_tau=False) # invalid identifiers with self.assertRaises(ValueError): plotting.plot_pulse_correlation_filter_function( concatenated_complicated_pulse, n_oper_identifiers=['foo'], fig=fig, axes=ax) # Test different axis scales scales = ('linear', 'log') for xscale in scales: for yscale in scales: fig, ax, leg = plotting.plot_pulse_correlation_filter_function( concatenated_simple_pulse, xscale=xscale, yscale=yscale) # Test various keyword args for matplotlib plot_kw = {'linewidth': 1} subplot_kw = {'facecolor': 'r'} gridspec_kw = {'hspace': 0.2, 'wspace': 0.1} figure_kw = {'num': 1} fig, ax, leg = plotting.plot_pulse_correlation_filter_function( concatenated_simple_pulse, plot_kw=plot_kw, subplot_kw=subplot_kw, gridspec_kw=gridspec_kw, **figure_kw) plt.close('all')
def test_calculation_with_unitaries(self): for d, G in zip(rng.randint(2, 9, (11, )), rng.randint(2, 11, (11, ))): pulses = [ testutil.rand_pulse_sequence(d, rng.randint(1, 11), 2, 4) for g in range(G) ] for pulse in pulses: # All pulses should have same n_opers for xxx_from_atomic pulse.n_opers = pulses[0].n_opers pulse.n_oper_identifiers = pulses[0].n_oper_identifiers if rng.randint(0, 2): pulse.t = None omega = rng.rand(17) B_atomic = np.array([ numeric.calculate_noise_operators_from_scratch( pulse.eigvals, pulse.eigvecs, pulse.propagators, omega, pulse.n_opers, pulse.n_coeffs, pulse.dt, pulse.t) for pulse in pulses ]) R_atomic = np.array([ numeric.calculate_control_matrix_from_scratch( pulse.eigvals, pulse.eigvecs, pulse.propagators, omega, pulse.basis, pulse.n_opers, pulse.n_coeffs, pulse.dt, pulse.t) for pulse in pulses ]) self.assertArrayAlmostEqual(ff.basis.expand(B_atomic, pulse.basis), R_atomic.transpose(0, 3, 1, 2), atol=1e-14) B = numeric.calculate_noise_operators_from_atomic( np.array([pulse.get_total_phases(omega) for pulse in pulses]), B_atomic, np.array([pulse.total_propagator for pulse in pulses])) R = numeric.calculate_control_matrix_from_atomic( np.array([pulse.get_total_phases(omega) for pulse in pulses]), R_atomic, np.array( [pulse.total_propagator_liouville for pulse in pulses])) self.assertArrayAlmostEqual(ff.basis.expand(B, pulse.basis), R.transpose(2, 0, 1), atol=1e-14)
def test_basis_generation_from_partial_ggm(self): """"Generate complete basis from partial elements of a GGM basis""" # Do 100 test runs with random elements from a GGM basis in (2 ... 8) # dimensions for _ in range(50): d = rng.randint(2, 9) b = ff.Basis.ggm(d) inds = [i for i in range(d**2)] tup = tuple( inds.pop(rng.randint(0, len(inds))) for _ in range(rng.randint(1, d**2))) elems = b[tup, ...] basis = ff.Basis(elems) self.assertTrue(basis.isorthonorm) self.assertTrue(basis.isherm) self.assertTrue(basis.istraceless) self.assertTrue(basis.iscomplete) self.assertTrue(all(elem in basis for elem in elems))
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.randint(2, 9, (15, )): # unitary channel U = testutil.rand_unit(d, rng.randint(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_remove_float_errors(self): for eps_scale in (None, 2): scale = eps_scale or 1 for dtype in (float, complex): arr = np.zeros((10, 10), dtype=dtype) arr += scale*np.finfo(arr.dtype).eps *\ rng.random_sample(arr.shape) arr[rng.randint(0, 2, arr.shape, dtype=bool)] *= -1 arr = util.remove_float_errors(arr, eps_scale) self.assertArrayEqual(arr, np.zeros(arr.shape, dtype=dtype))
def test_plot_filter_function(self): # Call with default args simple_pulse.cleanup('all') fig, ax, leg = plotting.plot_filter_function(simple_pulse) # Call with no axes but figure fig = plt.figure() fig, ax, leg = plotting.plot_filter_function(simple_pulse, fig=fig) # Call with axes but no figure fig, ax, leg = plotting.plot_filter_function(simple_pulse, axes=ax) # Non-default args n_oper_identifiers = sample( complicated_pulse.n_oper_identifiers.tolist(), rng.randint(2, 4)) fig, ax = plt.subplots() omega = ff.util.get_sample_frequencies(complicated_pulse, n_samples=50, spacing='log') fig, ax, leg = plotting.plot_filter_function( complicated_pulse, omega=omega, n_oper_identifiers=n_oper_identifiers, fig=fig, axes=ax, omega_in_units_of_tau=False) # invalid identifier with self.assertRaises(ValueError): plotting.plot_filter_function(complicated_pulse, n_oper_identifiers=['foo'], fig=fig, axes=ax) # Test different axis scales scales = ('linear', 'log') for xscale in scales: for yscale in scales: fig, ax, leg = plotting.plot_filter_function(simple_pulse, xscale=xscale, yscale=yscale) # Test various keyword args for matplotlib plot_kw = {'linewidth': 1} subplot_kw = {'facecolor': 'r'} gridspec_kw = {'hspace': 0.2, 'wspace': 0.1} figure_kw = {'num': 1} fig, ax, leg = plotting.plot_filter_function(simple_pulse, plot_kw=plot_kw, subplot_kw=subplot_kw, gridspec_kw=gridspec_kw, **figure_kw) plt.close('all')
def test_all_array_equal(self): for n in rng.randint(2, 10, (10, )): gen = (np.ones((10, 10)) for _ in range(n)) lst = [np.ones((10, 10)) for _ in range(n)] self.assertTrue(util.all_array_equal(gen)) self.assertTrue(util.all_array_equal(lst)) gen = (np.arange(9).reshape(3, 3) + i for i in range(n)) lst = [np.arange(9).reshape(3, 3) + i for i in range(n)] self.assertFalse(util.all_array_equal(gen)) self.assertFalse(util.all_array_equal(lst))
def test_concatenate_4_spin_echos(self): """Concatenate four Spin Echos with a random one having a filter function """ tau = 1 tau_pi = 1e-4 omega = np.logspace(-2, 1, 200) n = 1 H_c_SE, dt_SE = testutil.generate_dd_hamiltonian(n, tau=tau, tau_pi=tau_pi, dd_type='cpmg') H_n_SE = [[util.paulis[3], np.ones_like(dt_SE)]] SE = [ff.PulseSequence(H_c_SE, H_n_SE, dt_SE) for _ in range(4)] H_c_CPMG, dt_CPMG = testutil.generate_dd_hamiltonian(4*n, tau=4*tau, tau_pi=tau_pi, dd_type='cpmg') H_n_CPMG = [[util.paulis[3], np.ones_like(dt_CPMG)]] CPMG = ff.PulseSequence(H_c_CPMG, H_n_CPMG, dt_CPMG) SE[rng.randint(0, len(SE)-1)].cache_filter_function(omega) CPMG.cache_filter_function(omega) CPMG_concat_1 = ff.concatenate(SE) # Clean up so that we start from one SE with cached filter_function again for se in SE: se.cleanup('all') SE[rng.randint(0, len(SE)-1)].cache_filter_function(omega) CPMG_concat_2 = SE[0] @ SE[1] @ SE[2] @ SE[3] self.assertEqual(CPMG, CPMG_concat_1) self.assertEqual(CPMG, CPMG_concat_2) self.assertArrayAlmostEqual(CPMG_concat_1._filter_function, CPMG._filter_function, rtol=1e-10) self.assertArrayAlmostEqual(CPMG_concat_2._filter_function, CPMG._filter_function, rtol=1e-10)
def test_oper_equiv(self): with self.assertRaises(ValueError): util.oper_equiv(*[np.ones((1, 2, 3))] * 2) for d in rng.randint(2, 10, (5, )): psi = rng.standard_normal((d, 1)) + 1j * rng.standard_normal( (d, 1)) U = testutil.rand_herm(d).squeeze() phase = rng.standard_normal() result = util.oper_equiv(psi, psi * np.exp(1j * phase)) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(psi * np.exp(1j * phase), psi) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], -phase, places=5) psi /= np.linalg.norm(psi, ord=2) result = util.oper_equiv(psi, psi * np.exp(1j * phase), normalized=True, eps=1e-13) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(psi, psi + 1) self.assertFalse(result[0]) result = util.oper_equiv(U, U * np.exp(1j * phase)) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(U * np.exp(1j * phase), U) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], -phase, places=5) U /= np.sqrt(util.dot_HS(U, U)) result = util.oper_equiv(U, U * np.exp(1j * phase), normalized=True, eps=1e-10) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase) result = util.oper_equiv(U, U + 1) self.assertFalse(result[0])
def test_dot_HS(self): for d in rng.randint(2, 10, (5, )): U = qutip.rand_herm(d) V = qutip.rand_herm(d) self.assertArrayAlmostEqual(util.dot_HS(U, V), (U.dag() * V).tr()) U = qutip.rand_unitary(d) self.assertEqual(util.dot_HS(U, U), d) self.assertEqual(util.dot_HS(U, U + 1e-14, eps=1e-10), d) self.assertArrayAlmostEqual(util.dot_HS(U, V), (U.dag() * V).tr()) U = qutip.rand_unitary(d) self.assertEqual(util.dot_HS(U, U), d) self.assertEqual(util.dot_HS(U, U + 1e-14, eps=1e-10), d)
def test_infidelity_convergence(self): omega = { 'omega_IR': 0, 'omega_UV': 2, 'spacing': 'linear', 'n_min': 10, 'n_max': 50, 'n_points': 4 } def spectrum(omega): return omega**0 simple_pulse = testutil.rand_pulse_sequence(2, 1, 1, 1) complicated_pulse = testutil.rand_pulse_sequence(2, 100, 3, 3) with self.assertRaises(TypeError): n, infids = ff.infidelity(simple_pulse, spectrum, [], test_convergence=True) with self.assertRaises(TypeError): n, infids = ff.infidelity(simple_pulse, [1, 2, 3], dict(spacing='foobar'), test_convergence=True) with self.assertRaises(ValueError): n, infids = ff.infidelity(simple_pulse, spectrum, dict(spacing='foobar'), test_convergence=True) # Test with default args n, infids = ff.infidelity(simple_pulse, spectrum, {}, test_convergence=True) # Test with non-default args identifiers = rng.choice(complicated_pulse.n_oper_identifiers, rng.randint(1, 4)) n, infids = ff.infidelity(complicated_pulse, spectrum, omega, test_convergence=True, n_oper_identifiers=identifiers)
def test_basis_generation_from_partial_random(self): """"Generate complete basis from partial elements of a random basis""" # Do 25 test runs with random elements from a random basis in # (2 ... 8) dimensions for _ in range(25): d = rng.randint(2, 7) # Get a random traceless hermitian operator oper = testutil.rand_herm_traceless(d) # ... and build a basis from it b = ff.Basis(oper) self.assertTrue(b.isorthonorm) self.assertTrue(b.isherm) self.assertTrue(b.istraceless) self.assertTrue(b.iscomplete) # Choose random elements from that basis and generate a new basis # from it inds = [i for i in range(d**2)] tup = tuple( inds.pop(rng.randint(0, len(inds))) for _ in range(rng.randint(1, d**2))) elems = b[tup, ...] basis = ff.Basis(elems) self.assertTrue(basis.isorthonorm) self.assertTrue(basis.isherm) self.assertTrue(basis.istraceless) self.assertTrue(basis.iscomplete) self.assertTrue(all(elem in basis for elem in elems)) # Test runs with non-traceless opers for _ in range(25): d = rng.randint(2, 7) # Get a random hermitian operator oper = testutil.rand_herm(d) # ... and build a basis from it b = ff.Basis(oper) self.assertTrue(b.isorthonorm) self.assertTrue(b.isherm) self.assertFalse(b.istraceless) self.assertTrue(b.iscomplete) # Choose random elements from that basis and generate a new basis # from it inds = [i for i in range(d**2)] tup = tuple( inds.pop(rng.randint(0, len(inds))) for _ in range(rng.randint(1, d**2))) elems = b[tup, ...] basis = ff.Basis(elems) self.assertTrue(basis.isorthonorm) self.assertTrue(basis.isherm) self.assertFalse(basis.istraceless) self.assertTrue(basis.iscomplete) self.assertTrue(all(elem in basis for elem in elems))
def test_plot_pulse_train(self): # Call with default args fig, ax, leg = plotting.plot_pulse_train(simple_pulse) # Call with no axes but figure fig = plt.figure() fig, ax, leg = plotting.plot_pulse_train(simple_pulse, fig=fig) # Call with axes but no figure fig, ax, leg = plotting.plot_pulse_train(simple_pulse, axes=ax) # Call with custom args c_oper_identifiers = sample( complicated_pulse.c_oper_identifiers.tolist(), rng.randint(2, 4)) fig, ax = plt.subplots() fig, ax, leg = plotting.plot_pulse_train(complicated_pulse, c_oper_identifiers, fig=fig, axes=ax) # invalid identifier with self.assertRaises(ValueError): plotting.plot_pulse_train(complicated_pulse, c_oper_identifiers=['foo'], fig=fig, axes=ax) # Test various keyword args for matplotlib plot_kw = {'linewidth': 1} subplot_kw = {'facecolor': 'r'} gridspec_kw = {'hspace': 0.2, 'wspace': 0.1} figure_kw = {'num': 1} fig, ax, leg = plotting.plot_pulse_train(simple_pulse, plot_kw=plot_kw, subplot_kw=subplot_kw, gridspec_kw=gridspec_kw, **figure_kw) plt.close('all')
def test_oper_equiv(self): self.assertFalse( util.oper_equiv(qutip.rand_ket(2), qutip.rand_dm(2))[0]) for d in rng.randint(2, 10, (5, )): psi = qutip.rand_ket(d) U = qutip.rand_dm(d) phase = rng.standard_normal() result = util.oper_equiv(psi, psi * np.exp(1j * phase)) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(psi * np.exp(1j * phase), psi) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], -phase, places=5) result = util.oper_equiv(U, U * np.exp(1j * phase)) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], phase, places=5) result = util.oper_equiv(U * np.exp(1j * phase), U) self.assertTrue(result[0]) self.assertAlmostEqual(result[1], -phase, places=5)
def test_pulse_sequence_constructor(self): """Test constructing a PulseSequence.""" base_pulse = testutil.rand_pulse_sequence(2, 5, 3, 3) H_c = list(zip(base_pulse.c_opers, base_pulse.c_coeffs, base_pulse.c_oper_identifiers)) H_n = list(zip(base_pulse.n_opers, base_pulse.n_coeffs, base_pulse.n_oper_identifiers)) dt = base_pulse.dt for i in range(3): H_c[i] = list(H_c[i]) H_n[i] = list(H_n[i]) with self.assertRaises(TypeError): # Not enough positional arguments ff.PulseSequence(H_c, H_n) with self.assertRaises(TypeError): # dt not a sequence ff.PulseSequence(H_c, H_n, dt[0]) idx = rng.randint(0, 5) with self.assertRaises(ValueError): # negative dt dt[idx] *= -1 ff.PulseSequence(H_c, H_n, dt) dt[idx] *= -1 with self.assertRaises(ValueError): # imaginary dt dt = dt.astype(complex) dt[idx] += 1j ff.PulseSequence(H_c, H_n, dt) dt = dt.real basis = ff.Basis.pauli(1) with self.assertRaises(ValueError): # basis not Basis instance ff.PulseSequence(H_c, H_n, dt, basis.view(np.ndarray)) with self.assertRaises(ValueError): # basis not square ff.PulseSequence(H_c, H_n, dt, basis.reshape(4, 1, 4)) with self.assertRaises(TypeError): # Control Hamiltonian not list or tuple ff.PulseSequence(np.array(H_c, dtype=object), H_n, dt) with self.assertRaises(TypeError): # Noise Hamiltonian not list or tuple ff.PulseSequence(H_c, np.array(H_n, dtype=object), dt) with self.assertRaises(TypeError): # Element of control Hamiltonian not list or tuple ff.PulseSequence([np.array(H_c[0], dtype=object)], H_n, dt) with self.assertRaises(TypeError): # Element of noise Hamiltonian not list or tuple ff.PulseSequence(H_c, [np.array(H_n[0], dtype=object)], dt) idx = rng.randint(0, 3) with self.assertRaises(TypeError): # Control Hamiltonian element not list or tuple H_c[idx] = dict(H_c[idx]) ff.PulseSequence(H_c, H_n, dt) H_c[idx] = list(H_c[idx]) with self.assertRaises(TypeError): # Noise Hamiltonian element not list or tuple H_n[idx] = dict(H_n[idx]) ff.PulseSequence(H_c, H_n, dt) H_n[idx] = list(H_n[idx]) with self.assertRaises(TypeError): # Control operators wrong type oper = H_c[idx][0].copy() H_c[idx][0] = dict(H_c[idx][0]) ff.PulseSequence(H_c, H_n, dt) H_c[idx][0] = oper with self.assertRaises(TypeError): # Noise operators wrong type oper = H_n[idx][0].copy() H_n[idx][0] = dict(H_n[idx][0]) ff.PulseSequence(H_c, H_n, dt) H_n[idx][0] = oper with self.assertRaises(TypeError): # Control coefficients wrong type coeff = H_c[idx][1].copy() H_c[idx][1] = H_c[idx][1][0] ff.PulseSequence(H_c, H_n, dt) H_c[idx][1] = coeff with self.assertRaises(TypeError): # Noise coefficients wrong type coeff = H_n[idx][1].copy() H_n[idx][1] = H_n[idx][1][0] ff.PulseSequence(H_c, H_n, dt) H_n[idx][1] = coeff with self.assertRaises(ValueError): # Control operators not 2d for hc in H_c: hc[0] = np.tile(hc[0], (rng.randint(2, 11), 1, 1)) ff.PulseSequence(H_c, H_n, dt) for hc in H_c: hc[0] = hc[0][0] with self.assertRaises(ValueError): # Noise operators not 2d for hn in H_n: hn[0] = np.tile(hn[0], (rng.randint(2, 11), 1, 1)) ff.PulseSequence(H_c, H_n, dt) for hn in H_n: hn[0] = hn[0][0] with self.assertRaises(ValueError): # Control operators not square for hc in H_c: hc[0] = np.tile(hc[0].reshape(1, 4), (2, 1)) ff.PulseSequence(H_c, H_n, dt) for hc in H_c: hc[0] = hc[0][0].reshape(2, 2) with self.assertRaises(ValueError): # Noise operators not square for hn in H_n: hn[0] = np.tile(hn[0].reshape(1, 4), (2, 1)) ff.PulseSequence(H_c, H_n, dt) for hn in H_n: hn[0] = hn[0][0].reshape(2, 2) with self.assertRaises(ValueError): # Control and noise operators not same dimension for hn in H_n: hn[0] = np.block([[hn[0], hn[0]], [hn[0], hn[0]]]) ff.PulseSequence(H_c, H_n, dt) for hn in H_n: hn[0] = hn[0][:2, :2] with self.assertRaises(ValueError): # Control identifiers not unique identifier = H_c[idx][2] H_c[idx][2] = H_c[idx-1][2] ff.PulseSequence(H_c, H_n, dt) H_c[idx][2] = identifier with self.assertRaises(ValueError): # Noise identifiers not unique identifier = H_n[idx][2] H_n[idx][2] = H_n[idx-1][2] ff.PulseSequence(H_c, H_n, dt) H_n[idx][2] = identifier coeffs = [] with self.assertRaises(ValueError): # Control coefficients not same length as dt for hc in H_c: coeffs.append(hc[1][-2:]) hc[1] = hc[1][:-2] ff.PulseSequence(H_c, H_n, dt) for i, c in enumerate(coeffs): H_c[i][1] = np.concatenate((H_c[i][1], c)) with self.assertRaises(ValueError): # Noise coefficients not same length as dt for hn in H_n: hn[1] = hn[1][:-2] ff.PulseSequence(H_c, H_n, dt) for i, c in enumerate(coeffs): H_n[i][1] = np.concatenate((H_n[i][1], c)) pulse = ff.PulseSequence(H_c, H_n, dt) # Hit __str__ and __repr__ methods pulse print(pulse) # Hit __copy__ method _ = copy(pulse) # Fewer identifiers than opers pulse_2 = ff.PulseSequence( [[util.paulis[1], [1], 'X'], [util.paulis[2], [1]]], [[util.paulis[1], [1]], [util.paulis[2], [1], 'Y']], [1] ) self.assertArrayEqual(pulse_2.c_oper_identifiers, ('A_1', 'X')) self.assertArrayEqual(pulse_2.n_oper_identifiers, ('B_0', 'Y'))
def test_pulse_sequence_attributes(self): """Test attributes of single instance""" X, Y, Z = util.paulis[1:] n_dt = rng.randint(1, 10) # trivial case A = ff.PulseSequence([[X, rng.standard_normal(n_dt), 'X']], [[Z, rng.standard_normal(n_dt), 'Z']], np.abs(rng.standard_normal(n_dt))) self.assertFalse(A == 1) self.assertTrue(A != 1) # different number of time steps B = ff.PulseSequence([[X, rng.standard_normal(n_dt+1), 'X']], [[Z, rng.standard_normal(n_dt+1), 'Z']], np.abs(rng.standard_normal(n_dt+1))) self.assertFalse(A == B) self.assertTrue(A != B) # different time steps B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, A.c_oper_identifiers)), list(zip(A.n_opers, A.n_coeffs, A.n_oper_identifiers)), np.abs(rng.standard_normal(n_dt)) ) self.assertFalse(A == B) self.assertTrue(A != B) # different control opers B = ff.PulseSequence( list(zip([Y], A.c_coeffs, A.c_oper_identifiers)), list(zip(A.n_opers, A.n_coeffs, A.n_oper_identifiers)), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different control coeffs B = ff.PulseSequence( list(zip(A.c_opers, [rng.standard_normal(n_dt)], A.c_oper_identifiers)), list(zip(A.n_opers, A.n_coeffs, A.n_oper_identifiers)), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different noise opers B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, A.c_oper_identifiers)), list(zip([Y], A.n_coeffs, A.n_oper_identifiers)), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different noise coeffs B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, A.c_oper_identifiers)), list(zip(A.n_opers, [rng.standard_normal(n_dt)], A.n_oper_identifiers)), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different control oper identifiers B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, ['foobar'])), list(zip(A.n_opers, A.n_coeffs, A.n_oper_identifiers)), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different noise oper identifiers B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, A.c_oper_identifiers)), list(zip(A.n_opers, A.n_coeffs, ['foobar'])), A.dt ) self.assertFalse(A == B) self.assertTrue(A != B) # different bases elem = testutil.rand_herm_traceless(2) B = ff.PulseSequence( list(zip(A.c_opers, A.c_coeffs, A.c_oper_identifiers)), list(zip(A.n_opers, A.n_coeffs, A.n_oper_identifiers)), A.dt, ff.Basis(elem) ) self.assertFalse(A == B) self.assertTrue(A != B) # Test sparse operators for whatever reason A = ff.PulseSequence([[util.paulis[1], [1]]], [[sparse.COO.from_numpy(util.paulis[2]), [2]]], [3]) B = ff.PulseSequence([[sparse.COO.from_numpy(util.paulis[1]), [1]]], [[util.paulis[2], [2]]], [3]) self.assertEqual(A, B) # Test for attributes for attr in A.__dict__.keys(): if not (attr.startswith('_') or '_' + attr in A.__dict__.keys()): # not a cached attribute with self.assertRaises(AttributeError): _ = A.is_cached(attr) else: # set mock attribute at random if rng.randint(0, 2): setattr(A, attr, 'foo') assertion = self.assertTrue else: setattr(A, attr, None) assertion = self.assertFalse assertion(A.is_cached(attr)) # Diagonalization attributes A.diagonalize() self.assertIsNotNone(A.eigvals) self.assertIsNotNone(A.eigvecs) self.assertIsNotNone(A.propagators) A.cleanup('conservative') self.assertIsNotNone(A.eigvals) A.cleanup('conservative') self.assertIsNotNone(A.eigvecs) A.cleanup('conservative') self.assertIsNotNone(A.propagators) aliases = {'eigenvalues': '_eigvals', 'eigenvectors': '_eigvecs', 'total propagator': '_total_propagator', 'total propagator liouville': '_total_propagator_liouville', 'frequencies': '_omega', 'total phases': '_total_phases', 'filter function': '_filter_function', 'fidelity filter function': '_filter_function', 'generalized filter function': '_filter_function_gen', 'pulse correlation filter function': '_filter_function_pc', 'fidelity pulse correlation filter function': '_filter_function_pc', 'generalized pulse correlation filter function': '_filter_function_pc_gen', 'control matrix': '_control_matrix', 'pulse correlation control matrix': '_control_matrix_pc'} for alias, attr in aliases.items(): # set mock attribute at random if rng.randint(0, 2): setattr(A, attr, 'foo') assertion = self.assertTrue else: setattr(A, attr, None) assertion = self.assertFalse assertion(A.is_cached(alias)) assertion(A.is_cached(alias.upper())) assertion(A.is_cached(alias.replace(' ', '_'))) A.cleanup('all') # Test cleanup C = ff.concatenate((A, A), calc_pulse_correlation_FF=True, which='generalized', omega=util.get_sample_frequencies(A)) C.diagonalize() attrs = ['_eigvals', '_eigvecs', '_propagators'] for attr in attrs: self.assertIsNotNone(getattr(C, attr)) C.cleanup() for attr in attrs: self.assertIsNone(getattr(C, attr)) C.diagonalize() C.cache_control_matrix(A.omega) attrs.extend(['_control_matrix', '_total_phases', '_total_propagator', '_total_propagator_liouville']) for attr in attrs: self.assertIsNotNone(getattr(C, attr)) C.cleanup('greedy') for attr in attrs: self.assertIsNone(getattr(C, attr)) C.cache_filter_function(A.omega, which='generalized') for attr in attrs + ['omega', '_filter_function_gen', '_filter_function_pc_gen']: self.assertIsNotNone(getattr(C, attr)) C = ff.concatenate((A, A), calc_pulse_correlation_FF=True, which='fidelity', omega=A.omega) C.diagonalize() C.cache_filter_function(A.omega, which='fidelity') attrs.extend(['omega', '_filter_function', '_filter_function_pc']) for attr in attrs: self.assertIsNotNone(getattr(C, attr)) C.cleanup('all') for attr in attrs + ['_filter_function_gen', '_filter_function_pc_gen']: self.assertIsNone(getattr(C, attr)) C.cache_filter_function(A.omega, which='fidelity') C.cleanup('frequency dependent') freq_attrs = {'omega', '_control_matrix', '_filter_function', '_filter_function_gen', '_filter_function_pc', '_filter_function_pc_gen', '_total_phases'} for attr in freq_attrs: self.assertIsNone(getattr(C, attr)) for attr in set(attrs).difference(freq_attrs): self.assertIsNotNone(getattr(C, attr))
def test_filter_function(self): """Test the filter function calculation and related methods""" for d, n_dt in zip(rng.randint(2, 10, (3,)), rng.randint(10, 200, (3,))): total_pulse = testutil.rand_pulse_sequence(d, n_dt, 4, 6) c_opers, c_coeffs = total_pulse.c_opers, total_pulse.c_coeffs n_opers, n_coeffs = total_pulse.n_opers, total_pulse.n_coeffs dt = total_pulse.dt total_eigvals, total_eigvecs, _ = numeric.diagonalize( np.einsum('il,ijk->ljk', c_coeffs, c_opers), total_pulse.dt ) omega = util.get_sample_frequencies(total_pulse, n_samples=100) # Try the progress bar control_matrix = total_pulse.get_control_matrix( omega, show_progressbar=True) # Check that some attributes are cached self.assertIsNotNone(total_pulse._total_phases) self.assertIsNotNone(total_pulse._total_propagator) self.assertIsNotNone(total_pulse._total_propagator_liouville) # Calculate everything 'on foot' pulses = [ff.PulseSequence(list(zip(c_opers, c_coeffs[:, i:i+1])), list(zip(n_opers, n_coeffs[:, i:i+1])), dt[i:i+1]) for i in range(n_dt)] phases = np.empty((n_dt, len(omega)), dtype=complex) L = np.empty((n_dt, d**2, d**2)) control_matrix_g = np.empty((n_dt, 6, d**2, len(omega)), dtype=complex) for g, pulse in enumerate(pulses): phases[g] = np.exp(1j*total_pulse.t[g]*omega) L[g] = ff.superoperator.liouville_representation(total_pulse.propagators[g], total_pulse.basis) control_matrix_g[g] = pulse.get_control_matrix(omega) # Check that both methods of calculating the control are the same control_matrix_from_atomic = numeric.calculate_control_matrix_from_atomic( phases, control_matrix_g, L ) control_matrix_from_scratch = numeric.calculate_control_matrix_from_scratch( eigvals=total_eigvals, eigvecs=total_eigvecs, propagators=total_pulse.propagators, omega=omega, basis=total_pulse.basis, n_opers=n_opers, n_coeffs=n_coeffs, dt=total_pulse.dt ) self.assertArrayAlmostEqual(control_matrix, control_matrix_from_scratch) # first column (identity element) always zero but susceptible to # floating point error, increase atol self.assertArrayAlmostEqual(control_matrix_from_scratch, control_matrix_from_atomic, atol=1e-13) # Check if the filter functions for autocorrelated noise are real filter_function = total_pulse.get_filter_function(omega) self.assertTrue(np.isreal( filter_function[np.eye(len(n_opers), dtype=bool)] ).all()) # Check switch between fidelity and generalized filter function F_generalized = total_pulse.get_filter_function( omega, which='generalized') F_fidelity = total_pulse.get_filter_function( omega, which='fidelity') # Check that F_fidelity is correctly reduced from F_generalized self.assertArrayAlmostEqual(F_fidelity, F_generalized.trace(axis1=2, axis2=3)) # Hit getters again to check caching functionality F_generalized = total_pulse.get_filter_function( omega, which='generalized') F_fidelity = total_pulse.get_filter_function( omega, which='fidelity') # Check that F_fidelity is correctly reduced from F_generalized self.assertArrayAlmostEqual(F_fidelity, F_generalized.trace(axis1=2, axis2=3)) # Different set of frequencies than cached F_generalized = total_pulse.get_filter_function( omega + 1, which='generalized') F_fidelity = total_pulse.get_filter_function( omega + 1, which='fidelity') # Check that F_fidelity is correctly reduced from F_generalized self.assertArrayAlmostEqual(F_fidelity, F_generalized.trace(axis1=2, axis2=3))
def test_pulse_sequence_attributes_concat(self): """Test attributes of concatenated sequence.""" X, Y, Z = util.paulis[1:] n_dt_1 = rng.randint(5, 11) x_coeff_1 = rng.standard_normal(n_dt_1) z_coeff_1 = rng.standard_normal(n_dt_1) dt_1 = np.abs(rng.standard_normal(n_dt_1)) n_dt_2 = rng.randint(5, 11) y_coeff_2 = rng.standard_normal(n_dt_2) z_coeff_2 = rng.standard_normal(n_dt_2) dt_2 = np.abs(rng.standard_normal(n_dt_2)) pulse_1 = ff.PulseSequence([[X, x_coeff_1]], [[Z, z_coeff_1]], dt_1) pulse_2 = ff.PulseSequence([[Y, y_coeff_2]], [[Z, z_coeff_2]], dt_2) pulse_3 = ff.PulseSequence([[Y, rng.standard_normal(2)], [X, rng.standard_normal(2)]], [[Z, np.abs(rng.standard_normal(2))]], [1, 1]) # Concatenate with different noise opers pulses = [testutil.rand_pulse_sequence(2, 1) for _ in range(2)] pulses[0].omega = np.arange(10) pulses[1].omega = np.arange(10) newpulse = ff.concatenate(pulses, calc_filter_function=True) self.assertTrue(newpulse.is_cached('filter function')) pulse_12 = pulse_1 @ pulse_2 pulse_21 = pulse_2 @ pulse_1 with self.assertRaises(TypeError): _ = pulse_1 @ rng.standard_normal((2, 2)) # Concatenate pulses with same operators but different labels with self.assertRaises(ValueError): pulse_1 @ pulse_3 # Test nbytes property _ = pulse_1.nbytes self.assertArrayEqual(pulse_12.dt, [*dt_1, *dt_2]) self.assertArrayEqual(pulse_21.dt, [*dt_2, *dt_1]) self.assertArrayEqual(pulse_12.c_opers, [X, Y]) self.assertArrayEqual(pulse_21.c_opers, [Y, X]) self.assertArrayEqual(pulse_12.c_oper_identifiers, ['A_0_0', 'A_0_1']) self.assertArrayEqual(pulse_21.c_oper_identifiers, ['A_0_0', 'A_0_1']) self.assertArrayEqual(pulse_12.c_coeffs, [[*x_coeff_1, *np.zeros(n_dt_2)], [*np.zeros(n_dt_1), *y_coeff_2]]) self.assertArrayEqual(pulse_21.c_coeffs, [[*y_coeff_2, *np.zeros(n_dt_1)], [*np.zeros(n_dt_2), *x_coeff_1]]) self.assertArrayEqual(pulse_12.n_opers, [Z]) self.assertArrayEqual(pulse_21.n_opers, [Z]) self.assertArrayEqual(pulse_12.n_oper_identifiers, ['B_0']) self.assertArrayEqual(pulse_21.n_oper_identifiers, ['B_0']) self.assertArrayEqual(pulse_12.n_coeffs, [[*z_coeff_1, *z_coeff_2]]) self.assertArrayEqual(pulse_21.n_coeffs, [[*z_coeff_2, *z_coeff_1]]) omega = np.linspace(-100, 100, 101) pulses = (pulse_1, pulse_2, pulse_12, pulse_21) for pulse in pulses: self.assertIsNone(pulse._total_phases) self.assertIsNone(pulse._total_propagator) self.assertIsNone(pulse._total_propagator_liouville) total_phases = pulse.get_total_phases(omega) total_propagator = pulse.total_propagator total_propagator_liouville = pulse.total_propagator_liouville self.assertArrayEqual(total_phases, pulse._total_phases) self.assertArrayEqual(total_propagator, pulse._total_propagator) self.assertArrayEqual(total_propagator_liouville, pulse._total_propagator_liouville) # Test custom identifiers letters = rng.choice(list(string.ascii_letters), size=(6, 5), replace=False) ids = [''.join(c) for c in letters[:3]] labels = [''.join(c) for c in letters[3:]] pulse = ff.PulseSequence( list(zip([X, Y, Z], rng.standard_normal((3, 2)), ids, labels)), list(zip([X, Y, Z], rng.standard_normal((3, 2)), ids, labels)), [1, 1] ) self.assertArrayEqual(pulse.c_oper_identifiers, sorted(ids)) self.assertArrayEqual(pulse.n_oper_identifiers, sorted(ids))
def test_pulse_correlation_filter_function(self): """ Test calculation of pulse correlation filter function and control matrix. """ X, Y, Z = util.paulis[1:] T = 1 omega = np.linspace(-2e1, 2e1, 250) H_c, H_n, dt = dict(), dict(), dict() H_c['X'] = [[X, [np.pi/2/T]]] H_n['X'] = [[X, [1]], [Y, [1]], [Z, [1]]] dt['X'] = [T] H_c['Y'] = [[Y, [np.pi/4/T]]] H_n['Y'] = [[X, [1]], [Y, [1]], [Z, [1]]] dt['Y'] = [T] n_nops = 3 # Check if an exception is raised if we want to calculate the PC-FF but # one pulse has different frequencies with self.assertRaises(ValueError): pulses = dict() for i, key in enumerate(('X', 'Y')): pulses[key] = ff.PulseSequence(H_c[key], H_n[key], dt[key]) pulses[key].cache_filter_function(omega + i) ff.concatenate([pulses['X'], pulses['Y']], calc_pulse_correlation_FF=True) # Get filter functions at same frequencies [pulse.cache_filter_function(omega) for pulse in pulses.values()] pulse_1 = pulses['X'] @ pulses['Y'] pulse_2 = ff.concatenate([pulses['X'], pulses['Y']], calc_pulse_correlation_FF=True, which='fidelity') pulse_3 = ff.concatenate([pulses['X'], pulses['Y']], calc_pulse_correlation_FF=True, which='generalized') self.assertTrue(pulse_2.is_cached('control_matrix_pc')) self.assertTrue(pulse_2.is_cached('filter_function_pc')) self.assertTrue(pulse_3.is_cached('control_matrix_pc')) self.assertTrue(pulse_3.is_cached('filter_function_pc_gen')) # Check if the filter functions on the diagonals are real filter_function = pulse_2.get_pulse_correlation_filter_function() diag_1 = np.eye(2, dtype=bool) diag_2 = np.eye(3, dtype=bool) self.assertTrue(np.isreal(filter_function[diag_1][:, diag_2]).all()) self.assertEqual(pulse_1, pulse_2) self.assertEqual(pulse_2.get_pulse_correlation_filter_function().shape, (2, 2, n_nops, n_nops, len(omega))) self.assertArrayAlmostEqual( pulse_1.get_filter_function(omega), pulse_2.get_pulse_correlation_filter_function().sum((0, 1)) ) self.assertArrayAlmostEqual(pulse_1.get_filter_function(omega), pulse_2._filter_function) # Test the behavior of the pulse correlation control matrix with self.assertRaises(ValueError): # R wrong dimension numeric.calculate_pulse_correlation_filter_function( pulse_1._control_matrix) with self.assertRaises(util.CalculationError): # not calculated pulse_1.get_pulse_correlation_control_matrix() control_matrix_pc = pulse_2.get_pulse_correlation_control_matrix() self.assertArrayEqual( filter_function, numeric.calculate_pulse_correlation_filter_function( control_matrix_pc, 'fidelity' ) ) control_matrix_pc = pulse_3.get_pulse_correlation_control_matrix() filter_function = \ pulse_3.get_pulse_correlation_filter_function(which='fidelity') self.assertArrayEqual( filter_function, numeric.calculate_pulse_correlation_filter_function( control_matrix_pc, 'fidelity' ) ) filter_function = \ pulse_3.get_pulse_correlation_filter_function(which='generalized') self.assertArrayEqual( filter_function, numeric.calculate_pulse_correlation_filter_function( control_matrix_pc, 'generalized' ) ) # If for some reason filter_function_pc_xy is removed, check if # recovered from control_matrix_pc pulse_2._filter_function_pc = None pulse_3._filter_function_pc_gen = None control_matrix_pc = pulse_3.get_pulse_correlation_control_matrix() filter_function = \ pulse_3.get_pulse_correlation_filter_function(which='fidelity') self.assertArrayEqual( filter_function, numeric.calculate_pulse_correlation_filter_function( control_matrix_pc, 'fidelity' ) ) filter_function = \ pulse_3.get_pulse_correlation_filter_function(which='generalized') self.assertArrayEqual( filter_function, numeric.calculate_pulse_correlation_filter_function( control_matrix_pc, 'generalized' ) ) spectrum = omega**0*1e-2 with self.assertRaises(util.CalculationError): infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='correlations') with self.assertRaises(ValueError): infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='foobar') for _ in range(10): n_nops = rng.randint(1, 4) identifiers = sample(['B_0', 'B_1', 'B_2'], n_nops) infid_X = ff.infidelity(pulses['X'], spectrum, omega, which='total', n_oper_identifiers=identifiers) infid_Y = ff.infidelity(pulses['Y'], spectrum, omega, which='total', n_oper_identifiers=identifiers) infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='total', n_oper_identifiers=identifiers) infid_2 = ff.infidelity(pulse_2, spectrum, omega, which='correlations', n_oper_identifiers=identifiers) self.assertAlmostEqual(infid_1.sum(), infid_2.sum()) self.assertArrayAlmostEqual(infid_X, infid_2[0, 0]) self.assertArrayAlmostEqual(infid_Y, infid_2[1, 1]) # Test function for correlated noise spectra spectrum = np.array([[1e-4/omega**2, 1e-4*np.exp(-omega**2)], [1e-4*np.exp(-omega**2), 1e-4/omega**2]]) infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='total', n_oper_identifiers=['B_0', 'B_2']) infid_2 = ff.infidelity(pulse_2, spectrum, omega, which='correlations', n_oper_identifiers=['B_0', 'B_2']) self.assertAlmostEqual(infid_1.sum(), infid_2.sum()) self.assertArrayAlmostEqual(infid_1, infid_2.sum(axis=(0, 1)))