Ejemplo n.º 1
0
    def test_get_sample_frequencies(self):
        pulse = PulseSequence([[util.paulis[1], [np.pi / 2]]],
                              [[util.paulis[1], [1]]],
                              [abs(rng.standard_normal())])
        # Default args
        omega = util.get_sample_frequencies(pulse)
        self.assertAlmostEqual(omega[0], 2e-2 * np.pi / pulse.tau)
        self.assertAlmostEqual(omega[-1], 2e2 * np.pi / pulse.tau)
        self.assertEqual(len(omega), 300)
        self.assertTrue((omega >= 0).all())
        self.assertLessEqual(np.var(np.diff(np.log(omega[150:]))), 1e-16)

        # custom args
        omega = util.get_sample_frequencies(pulse,
                                            spacing='linear',
                                            n_samples=50,
                                            include_quasistatic=True)
        self.assertAlmostEqual(omega[0], 0)
        self.assertAlmostEqual(omega[-1], 2e2 * np.pi / pulse.tau)
        self.assertEqual(len(omega), 50)
        self.assertTrue((omega >= 0).all())
        self.assertLessEqual(np.var(np.diff(omega[1:])), 1e-16)

        # Exceptions
        with self.assertRaises(ValueError):
            omega = util.get_sample_frequencies(pulse, spacing='foo')
Ejemplo n.º 2
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)
Ejemplo n.º 3
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)
Ejemplo n.º 4
0
    def test_SE(self):
        """Spin echo"""
        tau = np.pi
        tau_pi = 1e-8
        n = 1

        H_c, dt = testutil.generate_dd_hamiltonian(n,
                                                   tau=tau,
                                                   tau_pi=tau_pi,
                                                   dd_type='cpmg')
        H_n = [[util.paulis[3] / 2, np.ones_like(dt)]]

        SE_pulse = ff.PulseSequence(H_c, H_n, dt)
        omega = util.get_sample_frequencies(SE_pulse, 100, spacing='linear')
        # Comparison to filter function defined with omega**2
        F = SE_pulse.get_filter_function(omega)[0, 0] * omega**2

        self.assertArrayAlmostEqual(F, analytic.SE(omega * tau), atol=1e-10)

        # Test again with a factor of one between the noise operators and
        # coefficients
        r = rng.standard_normal()
        H_n = [[util.paulis[3] / 2 * r, np.ones_like(dt) / r]]

        SE_pulse = ff.PulseSequence(H_c, H_n, dt)
        # Comparison to filter function defined with omega**2
        F = SE_pulse.get_filter_function(omega)[0, 0] * omega**2

        self.assertArrayAlmostEqual(F, analytic.SE(omega * tau), atol=1e-10)
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
    def test_FID(self):
        """FID"""
        tau = abs(rng.standard_normal())
        FID_pulse = ff.PulseSequence([[util.paulis[1] / 2, [0]]],
                                     [[util.paulis[3] / 2, [1]]], [tau])

        omega = util.get_sample_frequencies(FID_pulse, 50, spacing='linear')
        # Comparison to filter function defined with omega**2
        F = FID_pulse.get_filter_function(omega).squeeze() * omega**2

        self.assertArrayAlmostEqual(F, analytic.FID(omega * tau), atol=1e-10)
Ejemplo n.º 7
0
    def test_symmetrize_spectrum(self):
        pulse = PulseSequence(
            [[util.paulis[1], [np.pi/2]]],
            [[util.paulis[1], [1]]],
            [abs(rng.standard_normal())]
        )

        asym_omega = util.get_sample_frequencies(pulse, symmetric=False,
                                                 n_samples=100)
        sym_omega = util.get_sample_frequencies(pulse, symmetric=True,
                                                n_samples=200)

        S_symmetrized, omega_symmetrized = util.symmetrize_spectrum(
            1/asym_omega**0.7, asym_omega)
        self.assertArrayEqual(omega_symmetrized, sym_omega)
        self.assertArrayEqual(S_symmetrized[99::-1], S_symmetrized[100:])
        self.assertArrayEqual(S_symmetrized[100:]*2, 1/asym_omega**0.7)

        # zero frequency not doubled
        omega = np.arange(10)
        S_sym, omega_sym = util.symmetrize_spectrum(omega, omega)
        self.assertArrayEqual(S_sym, np.abs(np.arange(-9, 10)/2))
        self.assertArrayEqual(omega_sym, np.arange(-9, 10))
Ejemplo n.º 8
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))
Ejemplo n.º 9
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)
Ejemplo n.º 10
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)
Ejemplo n.º 11
0
    def test_6_pulse_CPMG(self):
        """6-pulse CPMG"""
        tau = np.pi
        tau_pi = 1e-9
        n = 6

        H_c, dt = testutil.generate_dd_hamiltonian(n,
                                                   tau=tau,
                                                   tau_pi=tau_pi,
                                                   dd_type='cpmg')
        H_n = [[util.paulis[3] / 2, np.ones_like(dt)]]

        CPMG_pulse = ff.PulseSequence(H_c, H_n, dt)
        omega = util.get_sample_frequencies(CPMG_pulse, 100, spacing='log')
        # Comparison to filter function defined with omega**2
        F = CPMG_pulse.get_filter_function(omega)[0, 0] * omega**2

        self.assertArrayAlmostEqual(F,
                                    analytic.CPMG(omega * tau, n),
                                    atol=1e-10)
Ejemplo n.º 12
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 = 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.from_partial(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)
Ejemplo n.º 13
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.randint(1, 11, 10):
            pulse = testutil.rand_pulse_sequence(d, n_dt, 3, 2, btype='Pauli')
            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
            # 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)
            # Calculate on foot (multi-qubit way)
            Gamma = numeric.calculate_decay_amplitudes(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(0))
            U_from_K = ff.error_transfer_matrix(cumulant_function=K)
            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(Up, U)
            self.assertArrayAlmostEqual(I_fidelity, I_decayamps)
            self.assertArrayAlmostEqual(I_transfer,
                                        I_fidelity.sum(),
                                        rtol=1e-4)
            self.assertArrayAlmostEqual(U, U_onfoot, atol=1e-14)
            self.assertArrayAlmostEqual(U_from_K, U_onfoot)

            # Different spectra for each noise oper
            S = np.outer(1e-6 * np.arange(1, 3), 400 / (omega**2 + 400))
            U = ff.error_transfer_matrix(pulse, S, omega)
            Up = ff.error_transfer_matrix(pulse,
                                          S,
                                          omega,
                                          memory_parsimonious=True)
            Gamma = numeric.calculate_decay_amplitudes(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(0))
            U_from_K = ff.error_transfer_matrix(cumulant_function=K)
            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(Up, U)
            self.assertArrayAlmostEqual(I_fidelity, I_decayamps)
            self.assertArrayAlmostEqual(I_transfer,
                                        I_fidelity.sum(),
                                        rtol=1e-4)
            self.assertArrayAlmostEqual(U, U_onfoot, atol=1e-14)
            self.assertArrayAlmostEqual(U_from_K, U_onfoot)

            # Cross-correlated spectra are complex, real part symmetric and
            # imaginary part antisymmetric
            S = 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)]])
            U = ff.error_transfer_matrix(pulse, S, omega)
            Up = ff.error_transfer_matrix(pulse,
                                          S,
                                          omega,
                                          memory_parsimonious=True)
            Gamma = numeric.calculate_decay_amplitudes(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((0, 1)))
            U_from_K = ff.error_transfer_matrix(cumulant_function=K)
            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(Up, U)
            self.assertArrayAlmostEqual(I_fidelity, I_decayamps)
            self.assertArrayAlmostEqual(I_transfer,
                                        I_fidelity.sum(),
                                        rtol=1e-4)
            self.assertArrayAlmostEqual(U, U_onfoot, atol=1e-14)
            self.assertArrayAlmostEqual(U_from_K, U_onfoot)
Ejemplo n.º 14
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)
Ejemplo n.º 15
0
    def test_accuracy(self):
        paulis = np.array(util.paulis)
        I, X, Y, Z = paulis
        amps = rng.standard_normal(rng.randint(1, 11))
        pulse = ff.PulseSequence(
            [[util.tensor(X, Y, Z), amps]],
            [[util.tensor(X, I, I), np.ones_like(amps), 'XII'],
             [util.tensor(I, X, I), np.ones_like(amps), 'IXI'],
             [util.tensor(I, I, X), np.ones_like(amps), 'IIX']],
            np.ones_like(amps),
            ff.Basis.pauli(3)
        )
        omega = util.get_sample_frequencies(pulse, 50)
        pulse.cache_filter_function(omega)

        for _ in range(100):
            order = rng.permutation(range(3))
            reordered_pulse = ff.PulseSequence(
                [[util.tensor(*paulis[1:][order]), amps]],
                [[util.tensor(*paulis[[1, 0, 0]][order]), np.ones_like(amps),
                  (''.join(['XII'[o] for o in order]))],
                 [util.tensor(*paulis[[0, 1, 0]][order]), np.ones_like(amps),
                  (''.join(['IXI'[o] for o in order]))],
                 [util.tensor(*paulis[[0, 0, 1]][order]), np.ones_like(amps),
                  (''.join(['IIX'[o] for o in order]))]],
                np.ones_like(amps),
                ff.Basis.pauli(3)
            )
            reordered_pulse.cache_filter_function(omega)

            remapped_pulse = ff.remap(
                pulse, order,
                oper_identifier_mapping={
                    'A_0': 'A_0',
                    'XII': ''.join(['XII'[o] for o in order]),
                    'IXI': ''.join(['IXI'[o] for o in order]),
                    'IIX': ''.join(['IIX'[o] for o in order])
                }
            )

            self.assertEqual(reordered_pulse, remapped_pulse)
            self.assertArrayAlmostEqual(reordered_pulse.t, remapped_pulse.t)
            self.assertEqual(reordered_pulse.d, remapped_pulse.d)
            self.assertEqual(reordered_pulse.basis, remapped_pulse.basis)
            self.assertArrayAlmostEqual(reordered_pulse._omega,
                                        remapped_pulse.omega)
            self.assertArrayAlmostEqual(reordered_pulse._propagators,
                                        remapped_pulse._propagators,
                                        atol=1e-14)
            self.assertArrayAlmostEqual(reordered_pulse._total_propagator,
                                        remapped_pulse._total_propagator,
                                        atol=1e-14)
            self.assertArrayAlmostEqual(
                reordered_pulse._total_propagator_liouville,
                remapped_pulse._total_propagator_liouville,
                atol=1e-14
            )
            self.assertArrayAlmostEqual(reordered_pulse._total_phases,
                                        remapped_pulse._total_phases)
            self.assertArrayAlmostEqual(reordered_pulse._control_matrix,
                                        remapped_pulse._control_matrix,
                                        atol=1e-12)
            self.assertArrayAlmostEqual(reordered_pulse._filter_function,
                                        remapped_pulse._filter_function,
                                        atol=1e-12)

            # Test the eigenvalues and -vectors by the characteristic equation
            self.assertCorrectDiagonalization(remapped_pulse, atol=1e-14)
Ejemplo n.º 16
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))
Ejemplo n.º 17
0
    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))
Ejemplo n.º 18
0
    def test_extend_with_identity(self):
        """Test extending a pulse to more qubits"""
        ID, X, Y, Z = util.paulis
        n_dt = 10
        coeffs = rng.standard_normal((3, n_dt))
        ids = ['X', 'Y', 'Z']
        pulse = ff.PulseSequence(
            list(zip((X, Y, Z), coeffs, ids)),
            list(zip((X, Y, Z), np.ones((3, n_dt)), ids)),
            np.ones(n_dt), basis=ff.Basis.pauli(1)
        )

        omega = util.get_sample_frequencies(pulse, spacing='log', n_samples=50)
        for N in rng.randint(2, 5, 4):
            for target in rng.randint(0, N-1, 2):
                pulse.cleanup('all')
                ext_opers = util.tensor(*np.insert(np.tile(ID, (N-1, 3, 1, 1)),
                                                   target, (X, Y, Z), axis=0))

                # By default, extend should add the target qubit as suffix to
                # identifiers
                ext_ids = [i + f'_{target}' for i in ids]
                ext_pulse = ff.PulseSequence(
                    list(zip(ext_opers, coeffs, ext_ids)),
                    list(zip(ext_opers, np.ones((3, n_dt)), ext_ids)),
                    np.ones(n_dt), basis=ff.Basis.pauli(N)
                )

                # Use custom mapping for identifiers and or labels
                letters = rng.choice(list(string.ascii_letters), size=(3, 5))
                mapped_ids = np.array([''.join(l) for l in letters])
                mapping = {i: new_id for i, new_id in zip(ids, mapped_ids)}
                ext_pulse_mapped_identifiers = ff.PulseSequence(
                    list(zip(ext_opers, coeffs, mapped_ids, ext_ids)),
                    list(zip(ext_opers, np.ones((3, n_dt)), mapped_ids,
                             ext_ids)),
                    np.ones(n_dt), basis=ff.Basis.pauli(N)
                )
                ext_pulse_mapped_labels = ff.PulseSequence(
                    list(zip(ext_opers, coeffs, ext_ids, mapped_ids)),
                    list(zip(ext_opers, np.ones((3, n_dt)), ext_ids,
                             mapped_ids)),
                    np.ones(n_dt), basis=ff.Basis.pauli(N)
                )
                ext_pulse_mapped_identifiers_labels = ff.PulseSequence(
                    list(zip(ext_opers, coeffs, mapped_ids)),
                    list(zip(ext_opers, np.ones((3, n_dt)), mapped_ids)),
                    np.ones(n_dt), basis=ff.Basis.pauli(N)
                )

                calc_filter_functionF = rng.randint(0, 2)
                if calc_filter_functionF:
                    # Expect things to be cached in extended pulse if original
                    # also was cached
                    pulse.cache_filter_function(omega)
                    ext_pulse.cache_filter_function(omega)

                test_ext_pulse = ff.extend([(pulse, target)], N, d_per_qubit=2)
                test_ext_pulse_mapped_identifiers = ff.extend(
                    [(pulse, target, mapping)], N, d_per_qubit=2
                )
                test_ext_pulse_mapped_labels = ff.extend(
                    [(pulse, target, None, mapping)], N, d_per_qubit=2
                )
                test_ext_pulse_mapped_identifiers_labels = ff.extend(
                    [(pulse, target, mapping, mapping)], N, d_per_qubit=2
                )

                self.assertEqual(ext_pulse, test_ext_pulse)
                self.assertEqual(ext_pulse_mapped_identifiers,
                                 test_ext_pulse_mapped_identifiers)
                self.assertEqual(ext_pulse_mapped_labels,
                                 test_ext_pulse_mapped_labels)
                self.assertEqual(ext_pulse_mapped_identifiers_labels,
                                 test_ext_pulse_mapped_identifiers_labels)

                if calc_filter_functionF:
                    self.assertCorrectDiagonalization(test_ext_pulse,
                                                      atol=1e-14)
                    self.assertArrayAlmostEqual(test_ext_pulse._propagators,
                                                ext_pulse._propagators, atol=1e-14)
                    self.assertArrayAlmostEqual(
                        test_ext_pulse._total_propagator_liouville,
                        ext_pulse._total_propagator_liouville,
                        atol=1e-14
                    )
                    self.assertArrayAlmostEqual(
                        test_ext_pulse._total_propagator,
                        ext_pulse._total_propagator,
                        atol=1e-14
                    )
                    self.assertArrayAlmostEqual(test_ext_pulse._total_phases,
                                                ext_pulse._total_phases)
                    self.assertArrayAlmostEqual(test_ext_pulse._control_matrix,
                                                ext_pulse._control_matrix, atol=1e-12)
                    self.assertArrayAlmostEqual(
                        test_ext_pulse._filter_function,
                        ext_pulse._filter_function,
                        atol=1e-12
                    )
                else:
                    self.assertIsNone(test_ext_pulse._eigvals)
                    self.assertIsNone(test_ext_pulse._eigvecs)
                    self.assertIsNone(test_ext_pulse._propagators)
                    self.assertIsNone(
                        test_ext_pulse._total_propagator_liouville)
                    self.assertIsNone(test_ext_pulse._total_propagator)
                    self.assertIsNone(test_ext_pulse._total_phases)
                    self.assertIsNone(test_ext_pulse._control_matrix)
                    self.assertIsNone(test_ext_pulse._filter_function)

                pulse.cleanup('all')
                ext_pulse.cleanup('all')
Ejemplo n.º 19
0
    def test_cumulant_function(self):
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)
        omega = rng.standard_normal(43)
        spectrum = rng.standard_normal(43)
        Gamma = numeric.calculate_decay_amplitudes(pulse, spectrum, omega)
        Delta = numeric.calculate_frequency_shifts(pulse, spectrum, omega)
        K_1 = numeric.calculate_cumulant_function(pulse, spectrum, omega)
        K_2 = numeric.calculate_cumulant_function(pulse,
                                                  decay_amplitudes=Gamma)
        K_3 = numeric.calculate_cumulant_function(pulse,
                                                  spectrum,
                                                  omega,
                                                  second_order=True)
        K_4 = numeric.calculate_cumulant_function(pulse,
                                                  decay_amplitudes=Gamma,
                                                  frequency_shifts=Delta,
                                                  second_order=True)
        self.assertArrayAlmostEqual(K_1, K_2)
        self.assertArrayAlmostEqual(K_3, K_4)

        with self.assertRaises(ValueError):
            # Neither spectrum + frequencies nor decay amplitudes supplied
            numeric.calculate_cumulant_function(pulse,
                                                None,
                                                None,
                                                decay_amplitudes=None)

        with self.assertRaises(ValueError):
            # Neither spectrum + frequencies nor frequency shifts supplied
            numeric.calculate_cumulant_function(pulse,
                                                None,
                                                None,
                                                frequency_shifts=None,
                                                second_order=True)

        with self.assertRaises(ValueError):
            # Trying to get correlation cumulant function for second order
            numeric.calculate_cumulant_function(pulse,
                                                spectrum,
                                                omega,
                                                second_order=True,
                                                which='correlations')

        with self.assertRaises(ValueError):
            # Using precomputed frequency shifts or decay amplitudes but different shapes
            numeric.calculate_cumulant_function(pulse,
                                                spectrum,
                                                omega,
                                                second_order=True,
                                                decay_amplitudes=Gamma[1:])

        with self.assertWarns(UserWarning):
            # Memory parsimonious only works for decay amplitudes
            numeric.calculate_cumulant_function(pulse,
                                                spectrum,
                                                omega,
                                                second_order=True,
                                                memory_parsimonious=True)

        for d in [2, *rng.integers(2, 7, 5)]:
            pulse = testutil.rand_pulse_sequence(d, 3, 2, 2)
            omega = util.get_sample_frequencies(pulse, n_samples=42)
            spectrum = 4e-3 / abs(omega)

            pulse.cache_control_matrix(omega, cache_intermediates=True)
            cumulant_function_first_order = numeric.calculate_cumulant_function(
                pulse, spectrum, omega, second_order=False)
            cumulant_function_second_order = numeric.calculate_cumulant_function(
                pulse, spectrum, omega, second_order=True)
            # Make sure first and second order are --roughly -- of same order
            # of magnitude. Unlike the frequency shifts themselves, the
            # second order contributions to the cumulant function vanish on the
            # diagonal, whereas the first order contributions dominate. Hence,
            # be quite lenient.
            second_order_contribution = (cumulant_function_second_order -
                                         cumulant_function_first_order)
            rel = (np.linalg.norm(cumulant_function_first_order) /
                   np.linalg.norm(second_order_contribution))

            # Second order terms should be anti-hermitian
            self.assertArrayAlmostEqual(
                second_order_contribution,
                -second_order_contribution.transpose(0, 2, 1),
                atol=1e-16)
            self.assertEqual(cumulant_function_first_order.shape,
                             cumulant_function_second_order.shape)
            self.assertLessEqual(rel, 200)
            self.assertGreaterEqual(rel, 1 / 10)
Ejemplo n.º 20
0
    def test_concatenate_without_filter_function(self):
        """Concatenate two Spin Echos without filter functions."""
        tau = 10
        tau_pi = 1e-4
        n = 1

        H_c_SE, dt_SE = testutil.generate_dd_hamiltonian(n, tau=tau,
                                                         tau_pi=tau_pi,
                                                         dd_type='cpmg')

        n_oper = util.paulis[3]
        H_n_SE = [[n_oper, np.ones_like(dt_SE)]]
        SE_1 = ff.PulseSequence(H_c_SE, H_n_SE, dt_SE)
        SE_2 = ff.PulseSequence(H_c_SE, H_n_SE, dt_SE)

        H_c_CPMG, dt_CPMG = testutil.generate_dd_hamiltonian(2*n, tau=2*tau,
                                                             tau_pi=tau_pi,
                                                             dd_type='cpmg')

        H_n_CPMG = [[n_oper, np.ones_like(dt_CPMG)]]
        CPMG = ff.PulseSequence(H_c_CPMG, H_n_CPMG, dt_CPMG)
        CPMG_concat = SE_1 @ SE_2

        self.assertEqual(CPMG_concat, CPMG)
        # Should still be None
        self.assertEqual(CPMG_concat._filter_function, CPMG._filter_function)

        # Test if calculation of composite filter function can be enforced with
        # omega != None
        omega = util.get_sample_frequencies(SE_1)
        CPMG_concat = ff.concatenate((SE_1, SE_2), omega=omega)
        self.assertIsNotNone(CPMG_concat._filter_function)

        pulse = testutil.rand_pulse_sequence(2, 1, 2, 3)
        # Concatenate pulses without filter functions
        with self.assertRaises(TypeError):
            # Not all pulse sequence
            pulse_sequence.concatenate_without_filter_function([pulse, 2])

        with self.assertRaises(TypeError):
            # Not iterable
            pulse_sequence.concatenate_without_filter_function(pulse)

        with self.assertRaises(ValueError):
            # Incompatible Hamiltonian shapes
            pulse_sequence.concatenate_without_filter_function(
                [testutil.rand_pulse_sequence(2, 1),
                 testutil.rand_pulse_sequence(3, 1)]
            )

        with self.assertRaises(ValueError):
            # Incompatible bases
            pulse = testutil.rand_pulse_sequence(4, 1, btype='GGM')
            cpulse = copy(pulse)
            cpulse.basis = ff.Basis.pauli(2)
            pulse_sequence.concatenate_without_filter_function([pulse, cpulse])

        pulse = pulse_sequence.concatenate_without_filter_function(
            [pulse, pulse], return_identifier_mappings=False
        )
        self.assertFalse(pulse.is_cached('filter function'))
Ejemplo n.º 21
0
    def test_caching(self):
        """Test caching"""
        pulse_1 = testutil.rand_pulse_sequence(2, 10, btype='Pauli')
        pulse_2 = testutil.rand_pulse_sequence(2, 10, btype='Pauli')
        pulse_2.dt = pulse_1.dt
        pulse_2.t = pulse_1.t
        omega = util.get_sample_frequencies(pulse_1, 50)

        # diagonalize one pulse
        pulse_1.diagonalize()
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)])
        self.assertIsNone(extended_pulse._eigvals)
        self.assertIsNone(extended_pulse._eigvecs)
        self.assertIsNone(extended_pulse._propagators)
        self.assertIsNone(extended_pulse._total_propagator)
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)

        # override
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)],
                                   cache_diagonalization=True)
        self.assertIsNotNone(extended_pulse._eigvals)
        self.assertIsNotNone(extended_pulse._eigvecs)
        self.assertIsNotNone(extended_pulse._propagators)
        self.assertIsNotNone(extended_pulse._total_propagator)
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)

        # diagonalize both
        pulse_2.diagonalize()
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)])
        self.assertIsNotNone(extended_pulse._eigvals)
        self.assertIsNotNone(extended_pulse._eigvecs)
        self.assertIsNotNone(extended_pulse._propagators)
        self.assertIsNotNone(extended_pulse._total_propagator)
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)

        # override
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)],
                                   cache_diagonalization=False)
        self.assertIsNone(extended_pulse._eigvals)
        self.assertIsNone(extended_pulse._eigvecs)
        self.assertIsNone(extended_pulse._propagators)
        # Total_propagators is still cached
        self.assertIsNotNone(extended_pulse._total_propagator)
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)

        # Get filter function for one pulse
        pulse_1.cache_filter_function(omega)
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)])
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)

        # override
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)],
                                   cache_filter_function=True,
                                   omega=omega)
        self.assertIsNotNone(extended_pulse._total_propagator_liouville)
        self.assertIsNotNone(extended_pulse._total_phases)
        self.assertIsNotNone(extended_pulse._control_matrix)
        self.assertIsNotNone(extended_pulse._filter_function)

        # Get filter function for both
        pulse_2.cache_filter_function(omega)
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)])
        self.assertIsNotNone(extended_pulse._total_propagator_liouville)
        self.assertIsNotNone(extended_pulse._total_phases)
        self.assertIsNotNone(extended_pulse._control_matrix)
        self.assertIsNotNone(extended_pulse._filter_function)

        # override
        extended_pulse = ff.extend([(pulse_1, 0), (pulse_2, 1)],
                                   cache_filter_function=False)
        self.assertIsNone(extended_pulse._total_propagator_liouville)
        self.assertIsNone(extended_pulse._total_phases)
        self.assertIsNone(extended_pulse._control_matrix)
        self.assertIsNone(extended_pulse._filter_function)