예제 #1
0
    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)
예제 #2
0
    def test_second_order_filter_function(self):
        for d, n_nops in zip(rng.integers(2, 7, 5), rng.integers(1, 5, 5)):
            pulse = testutil.rand_pulse_sequence(d, 3, 2, n_nops)
            omega = util.get_sample_frequencies(pulse, n_samples=42)

            # Make sure result is the same with or without intermediates
            pulse.cache_control_matrix(omega, cache_intermediates=True)
            F = pulse.get_filter_function(omega, order=1)
            F_1 = pulse.get_filter_function(omega, order=2)
            # Test caching
            F_2 = pulse.get_filter_function(omega, order=2)
            F_3 = numeric.calculate_second_order_filter_function(
                pulse.eigvals,
                pulse.eigvecs,
                pulse.propagators,
                omega,
                pulse.basis,
                pulse.n_opers,
                pulse.n_coeffs,
                pulse.dt,
                show_progressbar=False,
                intermediates=None)
            # Make sure first and second order are of same order of magnitude
            rel = np.linalg.norm(F) / np.linalg.norm(F_1)

            self.assertIs(F_1, F_2)
            self.assertArrayEqual(F_1, F_3)
            self.assertEqual(F_1.shape, (n_nops, n_nops, d**2, d**2, 42))
            self.assertLessEqual(rel, 10)
            self.assertGreaterEqual(rel, 1 / 10)
예제 #3
0
    def test_control_matrix(self):
        """Test control matrix for traceless and non-traceless bases"""

        n_opers = testutil.rand_herm(3, 4)
        n_opers_traceless = testutil.rand_herm_traceless(3, 4)

        basis = ff.Basis(testutil.rand_herm(3), traceless=False)
        basis_traceless = ff.Basis(testutil.rand_herm_traceless(3),
                                   traceless=True)

        base_pulse = testutil.rand_pulse_sequence(3, 10, 4, 4)

        omega = np.logspace(-1, 1, 51)

        for i, base in enumerate((basis, basis_traceless)):
            for j, n_ops in enumerate((n_opers, n_opers_traceless)):
                pulse = copy(base_pulse)
                pulse.n_opers = n_ops
                pulse.basis = base

                R = pulse.get_control_matrix(omega)

                if i == 0 and j == 0:
                    # base not traceless, nopers not traceless
                    self.assertTrue((R[:, 0] != 0).all())
                elif i == 0 and j == 1:
                    # base not traceless, nopers traceless
                    self.assertTrue((R[:, 0] != 0).all())
                elif i == 1 and j == 0:
                    # base traceless, nopers not traceless
                    self.assertTrue((R[:, 0] != 0).all())
                elif i == 1 and j == 1:
                    # base traceless, nopers traceless
                    self.assertTrue(np.allclose(R[:, 0], 0))
예제 #4
0
    def test_integration(self):
        """Compare integrals to numerical results."""
        d = 3
        pulse = testutil.rand_pulse_sequence(d, 5)
        # including zero
        E = util.get_sample_frequencies(pulse, 51, include_quasistatic=True)

        for i, (eigval, dt,
                t) in enumerate(zip(pulse.eigvals, pulse.dt, pulse.t)):
            integral, integral_numeric = _get_integrals_first_order(
                d, E, eigval, dt, t)
            self.assertArrayAlmostEqual(integral, integral_numeric, atol=1e-4)

            integral, integral_numeric = _get_integrals_second_order(
                d, E, eigval, dt, t)
            self.assertArrayAlmostEqual(integral, integral_numeric, atol=1e-4)

        # excluding (most likely) zero
        E = testutil.rng.standard_normal(51)

        for i, (eigval, dt,
                t) in enumerate(zip(pulse.eigvals, pulse.dt, pulse.t)):
            integral, integral_numeric = _get_integrals_first_order(
                d, E, eigval, dt, t)
            self.assertArrayAlmostEqual(integral, integral_numeric, atol=1e-4)

            integral, integral_numeric = _get_integrals_second_order(
                d, E, eigval, dt, t)
            self.assertArrayAlmostEqual(integral, integral_numeric, atol=1e-4)
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    def test_calculate_decay_amplitudes(self):
        """Test raises of numeric.calculate_decay_amplitudes"""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)

        omega = rng.standard_normal(43)
        # single spectrum
        spectrum = rng.standard_normal(78)
        for i in range(4):
            with self.assertRaises(ValueError):
                numeric.calculate_decay_amplitudes(pulse, np.tile(spectrum, [1]*i), omega)
예제 #8
0
    def test_calculate_error_vector_correlation_functions(self):
        """Test raises of numeric.error_transfer_matrix"""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)

        omega = rng.standard_normal(43)
        # single spectrum
        S = rng.standard_normal(78)
        for i in range(4):
            with self.assertRaises(ValueError):
                numeric.calculate_error_vector_correlation_functions(
                    pulse, np.tile(S, [1] * i), omega)
예제 #9
0
    def test_raises(self):
        pulse = testutil.rand_pulse_sequence(2, 3)
        omega = ff.util.get_sample_frequencies(pulse, n_samples=13)
        with self.assertRaises(ValueError):
            ff.infidelity_derivative(pulse,
                                     1 / omega,
                                     omega,
                                     control_identifiers=['long string'])

        with self.assertRaises(ValueError):
            pulse.get_filter_function_derivative(
                omega, n_coeffs_deriv=testutil.rng.normal(size=(2, 5, 10)))
예제 #10
0
    def test_error_transfer_matrix(self):
        """Test raises of numeric.error_transfer_matrix."""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)
        omega = testutil.rng.randn(43)
        spectrum = np.ones_like(omega)
        with self.assertRaises(ValueError):
            ff.error_transfer_matrix(pulse, spectrum)

        with self.assertRaises(TypeError):
            ff.error_transfer_matrix(cumulant_function=[1, 2, 3])

        with self.assertRaises(ValueError):
            ff.error_transfer_matrix(cumulant_function=testutil.rng.randn(2, 3, 4))
예제 #11
0
    def test_caching(self):
        """Make sure calculation works with or without cached intermediates."""

        for d, n_dt in zip(testutil.rng.integers(2, 5, 5),
                           testutil.rng.integers(2, 8, 5)):
            pulse = testutil.rand_pulse_sequence(d, n_dt)
            omega = ff.util.get_sample_frequencies(pulse, n_samples=27)
            spect = 1 / omega

            # Cache control matrix but not intermediates
            pulse.cache_control_matrix(omega, cache_intermediates=False)
            infid_nocache = ff.infidelity(pulse,
                                          spect,
                                          omega,
                                          cache_intermediates=False)
            infid_cache = ff.infidelity(pulse,
                                        spect,
                                        omega,
                                        cache_intermediates=True)

            self.assertArrayAlmostEqual(infid_nocache, infid_cache)

            cm_nocache = ff.gradient.calculate_derivative_of_control_matrix_from_scratch(
                omega,
                pulse.propagators,
                pulse.eigvals,
                pulse.eigvecs,
                pulse.basis,
                pulse.t,
                pulse.dt,
                pulse.n_opers,
                pulse.n_coeffs,
                pulse.c_opers,
                intermediates=dict())

            pulse.cleanup('frequency dependent')
            pulse.cache_control_matrix(omega, cache_intermediates=True)
            cm_cache = ff.gradient.calculate_derivative_of_control_matrix_from_scratch(
                omega,
                pulse.propagators,
                pulse.eigvals,
                pulse.eigvecs,
                pulse.basis,
                pulse.t,
                pulse.dt,
                pulse.n_opers,
                pulse.n_coeffs,
                pulse.c_opers,
                intermediates=pulse._intermediates)

            self.assertArrayAlmostEqual(cm_nocache, cm_cache)
예제 #12
0
    def test_liouville_is_cCP(self):
        for d in rng.integers(2, 9, (15, )):
            # (anti-) Hermitian generator, should always be cCP
            H = 1j * testutil.rand_herm(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)

            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])
예제 #13
0
    def test_calculate_cumulant_function(self):
        """Test numeric.calculate_cumulant_function"""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)

        omega = rng.standard_normal(43)
        # single spectrum
        spectrum = rng.standard_normal(43)
        Gamma = numeric.calculate_decay_amplitudes(pulse, spectrum, omega)
        K_1 = numeric.calculate_cumulant_function(pulse, spectrum, omega)
        K_2 = numeric.calculate_cumulant_function(pulse, decay_amplitudes=Gamma)
        self.assertArrayAlmostEqual(K_1, K_2)

        with self.assertRaises(ValueError):
            numeric.calculate_cumulant_function(pulse, None, None, None)
예제 #14
0
    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)
예제 #15
0
    def test_caching(self):
        pauli_pulse = testutil.rand_pulse_sequence(4, 1, 1, 4, 'Pauli')
        ggm_pulse = testutil.rand_pulse_sequence(4, 1, 1, 4, 'GGM')
        attrs = ('omega', 'eigvals', 'eigvecs', 'propagators', 'total_phases',
                 'total_propagator', 'filter_function',
                 'total_propagator_liouville', 'control_matrix')

        pauli_pulse.cleanup('all')
        remapped_pauli_pulse = ff.remap(pauli_pulse, (1, 0))
        for attr in attrs:
            self.assertEqual(pauli_pulse.is_cached(attr),
                             remapped_pauli_pulse.is_cached(attr))

        omega = util.get_sample_frequencies(pauli_pulse, n_samples=50)
        pauli_pulse.cache_filter_function(omega)
        remapped_pauli_pulse = ff.remap(pauli_pulse, (1, 0))
        for attr in attrs:
            self.assertEqual(pauli_pulse.is_cached(attr),
                             remapped_pauli_pulse.is_cached(attr))

        ggm_pulse.cleanup('all')
        remapped_ggm_pulse = ff.remap(ggm_pulse, (1, 0))
        for attr in attrs:
            self.assertEqual(ggm_pulse.is_cached(attr),
                             remapped_ggm_pulse.is_cached(attr))

        omega = util.get_sample_frequencies(ggm_pulse, n_samples=50)
        ggm_pulse.cache_filter_function(omega)
        with self.assertWarns(UserWarning):
            remapped_ggm_pulse = ff.remap(ggm_pulse, (1, 0))

        for attr in attrs[:-2]:
            self.assertEqual(ggm_pulse.is_cached(attr),
                             remapped_ggm_pulse.is_cached(attr))

        for attr in attrs[-2:]:
            self.assertFalse(remapped_ggm_pulse.is_cached(attr))
예제 #16
0
    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.integers(3, 7, 10), rng.integers(1, 6, 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)

            # Single spectrum, different spectra for each noise oper
            spectra = [
                1e-8 / omega**2,
                np.outer(1e-7 * (np.arange(n_nops) + 1),
                         400 / (omega**2 + 400))
            ]
            # Cross-correlated spectra which are complex, real part symmetric and
            # imaginary part antisymmetric
            spec = np.tile(1e-8 / abs(omega)**2,
                           (n_nops, n_nops, 1)).astype(complex)
            spec[np.triu_indices(n_nops, 1)].imag = 1e-10 * omega
            spec[np.tril_indices(
                n_nops, -1)].imag = -spec[np.triu_indices(n_nops, 1)].imag
            spectra.append(spec)

            for S in spectra:
                # Assert fidelity is same as computed by infidelity()
                U = ff.error_transfer_matrix(pulse, S, omega)
                # Calculate U in loop
                Up = ff.error_transfer_matrix(pulse,
                                              S,
                                              omega,
                                              memory_parsimonious=True)
                # Calculate second order
                U2 = ff.error_transfer_matrix(pulse,
                                              S,
                                              omega,
                                              second_order=True)
                I_fidelity = ff.infidelity(pulse, S, omega)
                I_transfer = 1 - np.einsum('...ii', U) / d**2
                I_transfer_2 = 1 - np.einsum('...ii', U2) / d**2
                self.assertArrayAlmostEqual(Up, U)
                self.assertArrayAlmostEqual(I_transfer,
                                            I_fidelity.sum(),
                                            atol=1e-4)
                self.assertArrayAlmostEqual(I_transfer_2,
                                            I_fidelity.sum(),
                                            atol=1e-4)
예제 #17
0
    def test_calculation_with_unitaries(self):
        for d, G in zip(rng.integers(2, 9, (11, )),
                        rng.integers(2, 11, (11, ))):
            pulses = [
                testutil.rand_pulse_sequence(d, rng.integers(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.integers(0, 2):
                    pulse._t = None

            omega = rng.random(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)
예제 #18
0
    def test_copy(self):
        pulse = testutil.rand_pulse_sequence(2, 2)
        old_copers = pulse.c_opers.copy()

        copied = copy.copy(pulse)
        deepcopied = copy.deepcopy(pulse)

        self.assertEqual(pulse, copied)
        self.assertEqual(pulse, deepcopied)

        pulse.c_opers[...] = rng.standard_normal(size=pulse.c_opers.shape)

        self.assertArrayEqual(pulse.c_opers, copied.c_opers)
        self.assertArrayEqual(old_copers, deepcopied.c_opers)

        self.assertEqual(pulse, copied)
        self.assertNotEqual(pulse, deepcopied)
예제 #19
0
    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))
예제 #20
0
    def test_cache_filter_function(self):
        omega = rng.random(32)
        pulse = testutil.rand_pulse_sequence(2, 3, n_nops=2)
        F_fidelity = numeric.calculate_filter_function(
            pulse.get_control_matrix(omega), 'fidelity')
        F_generalized = numeric.calculate_filter_function(
            pulse.get_control_matrix(omega), 'generalized')

        pulse.cache_filter_function(omega,
                                    filter_function=F_generalized,
                                    which='generalized')
        self.assertTrue(pulse.is_cached('filter function'))
        self.assertTrue(pulse.is_cached('generalized filter function'))

        self.assertArrayEqual(
            pulse.get_filter_function(omega, which='generalized'),
            F_generalized)
        self.assertArrayEqual(
            pulse.get_filter_function(omega, which='fidelity'), F_fidelity)
예제 #21
0
    def test_cache_intermediates(self):
        """Test caching of intermediate elements"""
        pulse = testutil.rand_pulse_sequence(3, 4, 2, 3)
        omega = util.get_sample_frequencies(pulse, 33, spacing='linear')
        ctrlmat = pulse.get_control_matrix(omega, cache_intermediates=True)
        filtfun = pulse.get_filter_function(omega, cache_intermediates=True)

        self.assertIsNotNone(pulse._intermediates)
        self.assertArrayAlmostEqual(pulse._intermediates['control_matrix_step'].sum(0), ctrlmat)
        self.assertArrayAlmostEqual(numeric.calculate_filter_function(ctrlmat), filtfun)
        self.assertArrayAlmostEqual(pulse._intermediates['n_opers_transformed'],
                                    numeric._transform_noise_operators(pulse.n_coeffs,
                                                                       pulse.n_opers,
                                                                       pulse.eigvecs))
        eigvecs_prop = numeric._propagate_eigenvectors(pulse.propagators[:-1], pulse.eigvecs)
        basis_transformed = np.einsum('gba,kbc,gcd->gkad',
                                      eigvecs_prop.conj(), pulse.basis, eigvecs_prop)
        self.assertArrayAlmostEqual(pulse._intermediates['basis_transformed'], basis_transformed,
                                    atol=1e-14)
예제 #22
0
    def test_filter_functions(self):
        """Filter functions equal for different bases"""
        # Set up random Hamiltonian
        base_pulse = testutil.rand_pulse_sequence(4, 3, 1, 1)
        omega = ff.util.get_sample_frequencies(base_pulse, n_samples=200)

        pauli_basis = ff.Basis.pauli(2)
        ggm_basis = ff.Basis.ggm(4)
        from_random_basis = ff.Basis(base_pulse.n_opers)
        bases = (pauli_basis, ggm_basis, from_random_basis)

        # Get Pulses with different bases
        F = []
        for b in bases:
            pulse = copy(base_pulse)
            pulse.basis = b
            F.append(pulse.get_filter_function(omega).sum(0))

        for pair in product(F, F):
            self.assertArrayAlmostEqual(*pair)
예제 #23
0
    def test_bloch_sphere_visualization_not_available(self):

        if matplotlib is not None:
            from filter_functions import plotting
        else:
            plotting = mock.Mock()

        with self.assertRaises(RuntimeError):
            plotting.get_bloch_vector(testutil.rng.standard_normal((10, 2)))

        with self.assertRaises(RuntimeError):
            plotting.init_bloch_sphere()

        with self.assertRaises(RuntimeError):
            plotting.plot_bloch_vector_evolution(
                testutil.rand_pulse_sequence(2, 1))

        from filter_functions import types
        self.assertIs(types.State, ndarray)
        self.assertIs(types.Operator, ndarray)
예제 #24
0
    def test_concatenate_base(self):
        """Basic functionality."""
        pulse_1, pulse_2 = [testutil.rand_pulse_sequence(2, 1, 2, 3)
                            for _ in range(2)]

        # Trivial case, copy
        c_pulse = ff.concatenate([pulse_1])
        self.assertEqual(pulse_1, c_pulse)
        self.assertFalse(pulse_1 is c_pulse)

        # Don't cache filter function, expect same result as with
        # concatenate_without_filter_function
        c_pulse_1 = ff.concatenate([pulse_1, pulse_2],
                                   calc_filter_function=False)
        c_pulse_2 = pulse_sequence.concatenate_without_filter_function(
            [pulse_1, pulse_2], return_identifier_mappings=False
        )
        self.assertEqual(c_pulse_1, c_pulse_2)

        # Try concatenation with different frequencies but FF calc. forced
        with self.assertRaises(ValueError):
            pulse_1.omega = [1, 2]
            pulse_2.omega = [3, 4]
            ff.concatenate([pulse_1, pulse_2], calc_filter_function=True)
예제 #25
0
    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'))
예제 #26
0
    def test_single_qubit_error_transfer_matrix(self):
        """Test the calculation of the single-qubit transfer matrix"""
        d = 2
        for n_dt in rng.integers(1, 11, 10):
            pulse = testutil.rand_pulse_sequence(d, n_dt, 3, 2, btype='Pauli')
            traceless = rng.integers(2, dtype=bool)
            if not traceless:
                # Test that result correct for finite trace n_oper (edge case)
                pulse.n_opers[0] = np.eye(d) / np.sqrt(d)

            omega = util.get_sample_frequencies(pulse, n_samples=51)
            n_oper_identifiers = pulse.n_oper_identifiers
            traces = pulse.basis.four_element_traces.todense()

            # Single spectrum, different spectra for each noise oper, and
            # Cross-correlated spectra which are complex, real part symmetric and
            # imaginary part antisymmetric
            spectra = [
                1e-8 / omega**2,
                np.outer(1e-6 * np.arange(1, 3), 400 / (omega**2 + 400)),
                np.array([[
                    1e-6 / abs(omega), 1e-8 / abs(omega) + 1j * 1e-8 / omega
                ], [1e-8 / abs(omega) - 1j * 1e-8 / omega, 2e-6 / abs(omega)]])
            ]

            for S in spectra:
                # Assert fidelity is same as computed by infidelity()
                U = ff.error_transfer_matrix(pulse, S, omega)
                # Calculate U in loop
                Up = ff.error_transfer_matrix(pulse,
                                              S,
                                              omega,
                                              memory_parsimonious=True)
                # Calculate on foot (multi-qubit way)
                Gamma = numeric.calculate_decay_amplitudes(
                    pulse, S, omega, n_oper_identifiers)
                Delta = numeric.calculate_frequency_shifts(
                    pulse, S, omega, n_oper_identifiers)
                K = -(np.einsum('...kl,klji->...ij', Gamma, traces) -
                      np.einsum('...kl,kjli->...ij', Gamma, traces) -
                      np.einsum('...kl,kilj->...ij', Gamma, traces) +
                      np.einsum('...kl,kijl->...ij', Gamma, traces)) / 2
                U_onfoot = sla.expm(K.sum(tuple(range(K.ndim - 2))))
                U_from_K = ff.error_transfer_matrix(cumulant_function=K)
                self.assertArrayAlmostEqual(Up, U)
                self.assertArrayAlmostEqual(U, U_onfoot, atol=1e-14)
                self.assertArrayAlmostEqual(U_from_K, U_onfoot)
                if traceless:
                    # Simplified fidelity calculation relies on traceless n_opers
                    I_fidelity = ff.infidelity(pulse, S, omega)
                    I_decayamps = -np.einsum('...ii', K) / d**2
                    I_transfer = 1 - np.einsum('...ii', U) / d**2
                    self.assertArrayAlmostEqual(I_fidelity, I_decayamps)
                    self.assertArrayAlmostEqual(I_transfer,
                                                I_fidelity.sum(),
                                                rtol=1e-4,
                                                atol=1e-10)

                # second order
                K -= (np.einsum('...kl,klji->...ij', Delta, traces) -
                      np.einsum('...kl,lkji->...ij', Delta, traces) -
                      np.einsum('...kl,klij->...ij', Delta, traces) +
                      np.einsum('...kl,lkij->...ij', Delta, traces)) / 2
                U = ff.error_transfer_matrix(pulse,
                                             S,
                                             omega,
                                             second_order=True)
                U_onfoot = sla.expm(K.sum(tuple(range(K.ndim - 2))))
                U_from_K = ff.error_transfer_matrix(cumulant_function=K)
                self.assertArrayAlmostEqual(U, U_onfoot, atol=1e-14)
                self.assertArrayAlmostEqual(U_from_K, U_onfoot)
                if traceless:
                    # Simplified fidelity calculation relies on traceless n_opers
                    I_transfer = 1 - np.einsum('...ii', U) / d**2
                    self.assertArrayAlmostEqual(I_transfer,
                                                I_fidelity.sum(),
                                                rtol=1e-4,
                                                atol=1e-10)
예제 #27
0
    def test_infidelity(self):
        """Benchmark infidelity results against previous version's results"""
        rng = np.random.default_rng(seed=123456789)

        spectra = [
            lambda S0, omega: S0 * abs(omega)**0,
            lambda S0, omega: S0 / abs(omega)**0.7,
            lambda S0, omega: S0 * np.exp(-abs(omega)),
            # different spectra for different n_opers
            lambda S0, omega: np.array(
                [S0 * abs(omega)**0, S0 / abs(omega)**0.7]),
            # cross-correlated spectra
            lambda S0, omega: np.array([[
                S0 / abs(omega)**0.7, S0 / (1 + omega**2) + 1j * S0 * omega
            ], [S0 / (1 + omega**2) - 1j * S0 * omega, S0 / abs(omega)**0.7]])
        ]

        ref_infids = ([[2.1571674053883583, 2.1235628100639845],
                       [1.7951695420688032, 2.919850951578396],
                       [0.4327173760925169, 0.817672660809546],
                       [2.1571674053883583, 2.919850951578396],
                       [[1.7951695420688032, -1.1595479985471822],
                        [-1.1595479985471822, 2.919850951578396]],
                       [0.8247284959004152, 2.495561429509174],
                       [0.854760904366362, 3.781670732974073],
                       [0.24181791977082442, 1.122626106375816],
                       [0.8247284959004152, 3.781670732974073],
                       [[0.854760904366362, -0.16574972846239408],
                        [-0.16574972846239408, 3.781670732974073]],
                       [2.9464977186365267, 0.8622319594213088],
                       [2.8391133843027525, 0.678843575761492],
                       [0.813728718501677, 0.16950739577216872],
                       [2.9464977186365267, 0.678843575761492],
                       [[2.8391133843027525, 0.2725782717379744],
                        [0.2725782717379744, 0.678843575761492]]])

        count = 0
        for d in (2, 3, 4):
            pulse = testutil.rand_pulse_sequence(d, 10, 2, 3, local_rng=rng)
            pulse.n_oper_identifiers = np.array(['B_0', 'B_2'])

            omega = np.geomspace(0.1, 10, 51)
            S0 = np.abs(rng.standard_normal())
            for spec in spectra:
                S = spec(S0, omega)
                infids = ff.infidelity(pulse,
                                       S,
                                       omega,
                                       n_oper_identifiers=['B_0', 'B_2'])
                self.assertArrayAlmostEqual(infids,
                                            ref_infids[count],
                                            atol=1e-12)
                if S.ndim == 3:
                    # Diagonal of the infidelity matrix should correspond to
                    # uncorrelated terms
                    uncorrelated_infids = ff.infidelity(
                        pulse,
                        S[range(2), range(2)],
                        omega,
                        n_oper_identifiers=['B_0', 'B_2'])
                    self.assertArrayAlmostEqual(np.diag(infids),
                                                uncorrelated_infids)
                    # Infidelity matrix should be hermitian
                    self.assertArrayEqual(infids, infids.conj().T)

                count += 1

        # Check raises
        with self.assertRaises(TypeError):
            # spectrum not callable
            ff.infidelity(pulse, 2, omega, test_convergence=True)

        with self.assertRaises(TypeError):
            # omega not dict
            ff.infidelity(pulse, lambda x: x, 2, test_convergence=True)

        with self.assertRaises(ValueError):
            # omega['spacing'] not in ('linear', 'log')
            ff.infidelity(pulse,
                          lambda x: x, {'spacing': 2},
                          test_convergence=True)

        with self.assertRaises(ValueError):
            # which not total or correlation
            ff.infidelity(pulse, spectra[0](S0, omega), omega, which=2)

        with self.assertRaises(ValueError):
            # S wrong dimensions
            ff.infidelity(pulse, spectra[0](S0, omega)[:10], omega)

        with self.assertRaises(ValueError):
            # S wrong dimensions
            ff.infidelity(pulse,
                          spectra[3](S0, omega),
                          omega,
                          n_oper_identifiers=['B_0', 'B_1', 'B_2'])

        with self.assertRaises(ValueError):
            # S wrong dimensions
            ff.infidelity(pulse,
                          spectra[4](S0, omega)[:, [0]],
                          omega,
                          n_oper_identifiers=['B_0'])

        with self.assertRaises(ValueError):
            # S wrong dimensions
            ff.infidelity(pulse, rng.standard_normal((2, 3, 4, len(omega))),
                          omega)

        with self.assertRaises(ValueError):
            # S wrong dimensions
            ff.infidelity(testutil.rand_pulse_sequence(2, 3, n_nops=2),
                          rng.standard_normal((3, 2, 2, len(omega))), omega)

        with self.assertRaises(ValueError):
            # S cross-correlated but not hermitian
            ff.infidelity(testutil.rand_pulse_sequence(2, 3, n_nops=2),
                          rng.standard_normal((2, 2, len(omega))), omega)

        with self.assertRaises(ValueError):
            # S 'cross-correlated' but not hermitian
            ff.infidelity(pulse, (1 + 1j) * rng.standard_normal(
                (1, 1, len(omega))), omega)

        with self.assertRaises(NotImplementedError):
            # smallness parameter for correlated noise source
            ff.infidelity(pulse,
                          spectra[4](S0, omega),
                          omega,
                          n_oper_identifiers=['B_0', 'B_2'],
                          return_smallness=True)
예제 #28
0
    def test_integrals_against_numeric(self):
        """Test the private function used to set up the integrand."""
        pulses = [
            testutil.rand_pulse_sequence(3, 1, 2, 3),
            testutil.rand_pulse_sequence(3, 1, 2, 3)
        ]
        pulses[1].n_opers = pulses[0].n_opers
        pulses[1].n_oper_identifiers = pulses[0].n_oper_identifiers

        omega = np.linspace(-1, 1, 50)
        spectra = [
            1e-6 / abs(omega),
            1e-6 / np.power.outer(abs(omega), np.arange(2)).T,
            np.array([[
                1e-6 / abs(omega)**0.7,
                1e-6 / (1 + omega**2) + 1j * 1e-6 * omega
            ],
                      [
                          1e-6 / (1 + omega**2) - 1j * 1e-6 * omega,
                          1e-6 / abs(omega)**0.7
                      ]])
        ]

        pulse = ff.concatenate(pulses,
                               omega=omega,
                               calc_pulse_correlation_FF=True)

        idx = testutil.rng.choice(np.arange(2),
                                  testutil.rng.integers(1, 3),
                                  replace=False)

        R = pulse.get_control_matrix(omega)
        R_pc = pulse.get_pulse_correlation_control_matrix()
        F = pulse.get_filter_function(omega)
        F_kl = pulse.get_filter_function(omega, 'generalized')
        F_pc = pulse.get_pulse_correlation_filter_function()
        F_pc_kl = pulse.get_pulse_correlation_filter_function('generalized')

        for i, spectrum in enumerate(spectra):
            if i == 0:
                S = spectrum
            elif i == 1:
                S = spectrum[idx]
            elif i == 2:
                S = spectrum[idx[None, :], idx[:, None]]

            R_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='fidelity',
                                         control_matrix=R,
                                         filter_function=None)
            R_2 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='fidelity',
                                         control_matrix=[R, R],
                                         filter_function=None)
            F_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='fidelity',
                                         control_matrix=None,
                                         filter_function=F)

            self.assertArrayAlmostEqual(R_1, R_2)
            self.assertArrayAlmostEqual(R_1, F_1)

            R_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='fidelity',
                                         control_matrix=R_pc,
                                         filter_function=None)
            R_2 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='fidelity',
                                         control_matrix=[R_pc, R_pc],
                                         filter_function=None)
            F_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='fidelity',
                                         control_matrix=None,
                                         filter_function=F_pc)

            self.assertArrayAlmostEqual(R_1, R_2)
            self.assertArrayAlmostEqual(R_1, F_1)

            R_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='generalized',
                                         control_matrix=R,
                                         filter_function=None)
            R_2 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='generalized',
                                         control_matrix=[R, R],
                                         filter_function=None)
            F_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='total',
                                         which_FF='generalized',
                                         control_matrix=None,
                                         filter_function=F_kl)

            self.assertArrayAlmostEqual(R_1, R_2)
            self.assertArrayAlmostEqual(R_1, F_1)

            R_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='generalized',
                                         control_matrix=R_pc,
                                         filter_function=None)
            R_2 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='generalized',
                                         control_matrix=[R_pc, R_pc],
                                         filter_function=None)
            F_1 = numeric._get_integrand(S,
                                         omega,
                                         idx,
                                         which_pulse='correlations',
                                         which_FF='generalized',
                                         control_matrix=None,
                                         filter_function=F_pc_kl)

            self.assertArrayAlmostEqual(R_1, R_2)
            self.assertArrayAlmostEqual(R_1, F_1)
예제 #29
0
    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))
예제 #30
0
    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))