def test_diagonalization_cnot(self):
        """CNOT"""
        cnot_mat = np.block([[util.paulis[0], np.zeros((2, 2))],
                             [np.zeros((2, 2)), util.paulis[1]]])

        subspace_c_opers = testutil.subspace_opers
        subspace_n_opers = subspace_c_opers
        c_opers = testutil.opers
        n_opers = c_opers
        c_coeffs, n_coeffs = testutil.c_coeffs, testutil.n_coeffs
        dt = testutil.dt
        subspace = testutil.subspace

        cnot_subspace = ff.PulseSequence(list(zip(subspace_c_opers, c_coeffs)),
                                         list(zip(subspace_n_opers, n_coeffs)),
                                         dt)

        cnot = ff.PulseSequence(list(zip(c_opers, c_coeffs)),
                                list(zip(n_opers, n_coeffs)), dt)

        cnot.diagonalize()
        cnot_subspace.diagonalize()

        phase_eq = ff.util.oper_equiv(cnot_subspace.total_propagator[1:5, 1:5],
                                      cnot_mat,
                                      eps=1e-9)

        self.assertTrue(phase_eq[0])

        phase_eq = ff.util.oper_equiv(
            cnot.total_propagator[np.ix_(*subspace)][1:5, 1:5],
            cnot_mat,
            eps=1e-9)

        self.assertTrue(phase_eq[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)
Exemple #3
0
    def test_concatenation_periodic(self):
        """Test concatenation for periodic Hamiltonians"""
        X, Y, Z = util.paulis[1:]
        A = 0.01
        omega_0 = 1
        omega_d = omega_0
        tau = np.pi/A
        omega = np.logspace(np.log10(omega_0) - 3, np.log10(omega_0) + 3, 1001)

        t = np.linspace(0, tau, 1001)
        dt = np.diff(t)
        H_c = [[Z, [omega_0/2]*len(dt)],
               [X, A*np.cos(omega_d*t[1:])]]
        H_n = [[Z, np.ones_like(dt)],
               [X, np.ones_like(dt)]]

        NOT_LAB = ff.PulseSequence(H_c, H_n, dt)
        F_LAB = NOT_LAB.get_filter_function(omega)

        T = 2*np.pi/omega_d
        G = round(tau/T)
        t = np.linspace(0, T, int(T/NOT_LAB.dt[0])+1)
        dt = np.diff(t)

        H_c = [[Z, [omega_0/2]*len(dt)],
               [X, A*np.cos(omega_d*t[1:])]]
        H_n = [[Z, np.ones_like(dt)],
               [X, np.ones_like(dt)]]

        ATOMIC = ff.PulseSequence(H_c, H_n, dt)
        ATOMIC.cache_filter_function(omega)

        NOT_CC = ff.concatenate((ATOMIC for _ in range(G)))
        F_CC = NOT_CC.get_filter_function(omega)
        NOT_CC_PERIODIC = ff.concatenate_periodic(ATOMIC, G)
        F_CC_PERIODIC = NOT_CC_PERIODIC.get_filter_function(omega)

        # Have to do manual comparison due to floating point error. The high
        # rtol is due to 1e-21/1e-19 occurring once.
        attrs = ('dt', 'c_opers', 'c_coeffs', 'n_opers', 'n_coeffs')
        for attr in attrs:
            self.assertArrayAlmostEqual(getattr(NOT_LAB, attr),
                                        getattr(NOT_CC, attr),
                                        atol=1e-15, rtol=1e2)
            self.assertArrayAlmostEqual(getattr(NOT_LAB, attr),
                                        getattr(NOT_CC_PERIODIC, attr),
                                        atol=1e-15, rtol=1e2)

        # Check if stuff is cached
        self.assertIsNotNone(NOT_CC._total_phases)
        self.assertIsNotNone(NOT_CC._total_propagator)
        self.assertIsNotNone(NOT_CC._total_propagator_liouville)
        # concatenate_periodic does not cache phase factors
        self.assertIsNotNone(NOT_CC_PERIODIC._total_phases)
        self.assertIsNotNone(NOT_CC_PERIODIC._total_propagator)
        self.assertIsNotNone(NOT_CC_PERIODIC._total_propagator_liouville)

        self.assertArrayAlmostEqual(F_LAB, F_CC, atol=1e-13)
        self.assertArrayAlmostEqual(F_LAB, F_CC_PERIODIC, atol=1e-13)
Exemple #4
0
 def test_pulse_sequence_constructor(self):
     X, Y, Z = qutip.sigmax(), qutip.sigmay(), qutip.sigmaz()
     pulse_1 = ff.PulseSequence(
         [[X, [1, 2, 3], 'X'], [util.paulis[2], [3, 4, 5], 'Y'],
          [Z, [5, 6, 7], 'Z']],
         [[util.paulis[3], [1, 2, 3], 'Z'], [Y, [3, 4, 5], 'Y'],
          [util.paulis[1], [5, 6, 7], 'X']], [1, 3, 5])
     pulse_2 = ff.PulseSequence(
         [[Y, [3, 4, 5], 'Y'], [util.paulis[3], [5, 6, 7], 'Z'],
          [util.paulis[1], [1, 2, 3], 'X']],
         [[X, [5, 6, 7], 'X'], [Z, [1, 2, 3], 'Z'],
          [util.paulis[2], [3, 4, 5], 'Y']], [1, 3, 5])
     self.assertEqual(pulse_1, pulse_2)
    def test_infidelity_cnot(self):
        """Compare infidelity to monte carlo results"""
        c_opers = testutil.subspace_opers
        n_opers = c_opers
        c_coeffs, n_coeffs = testutil.c_coeffs, testutil.n_coeffs
        dt = testutil.dt
        infid_MC = testutil.cnot_infid_fast
        A = testutil.A

        # Basis for qubit subspace
        qubit_subspace_basis = ff.Basis(
            [np.pad(b, 1, 'constant') for b in ff.Basis.pauli(2)],
            skip_check=True,
            btype='Pauli')
        complete_basis = ff.Basis(qubit_subspace_basis,
                                  traceless=False,
                                  btype='Pauli')

        identifiers = ['eps_12', 'eps_23', 'eps_34', 'b_12', 'b_23', 'b_34']
        H_c = list(zip(c_opers, c_coeffs, identifiers))
        H_n = list(zip(n_opers, n_coeffs, identifiers))
        cnot = ff.PulseSequence(H_c, H_n, dt, basis=qubit_subspace_basis)
        cnot_full = ff.PulseSequence(H_c, H_n, dt, basis=complete_basis)

        # Manually set dimension of pulse as the dimension of the computational
        # subspace
        cnot.d = 4
        T = dt.sum()

        for f_min, A, alpha, MC, rtol in zip((1 / T, 1e-2 / T), A, (0.0, 0.7),
                                             infid_MC, (0.04, 0.02)):

            omega = np.geomspace(f_min, 1e2, 250) * 2 * np.pi
            S_t, omega_t = ff.util.symmetrize_spectrum(A / omega**alpha, omega)

            infid, xi = ff.infidelity(cnot,
                                      S_t,
                                      omega_t,
                                      identifiers[:3],
                                      return_smallness=True)

            U = ff.error_transfer_matrix(cnot_full, S_t, omega_t,
                                         identifiers[:3])
            infid_P = np.trace(U[:, :16, :16], axis1=1, axis2=2).real / 4**2

            print(np.abs(1 - (infid.sum() / MC)))
            print(np.abs(1 - (infid_P.sum() / MC)))
            self.assertLessEqual(np.abs(1 - (infid.sum() / MC)), rtol)
            self.assertLessEqual(np.abs(1 - (infid_P.sum() / MC)), rtol)
            self.assertLessEqual(infid.sum(), xi**2 / 4)
    def test_infidelity_cnot(self):
        """Compare infidelity to monte carlo results"""
        c_opers = testutil.subspace_opers
        n_opers = c_opers
        c_coeffs, n_coeffs = testutil.c_coeffs, testutil.n_coeffs
        dt = testutil.dt
        infid_MC = testutil.cnot_infid_fast
        A = testutil.A

        # Basis for qubit subspace
        qubit_subspace_basis = ff.Basis(
            [np.pad(b, 1, 'constant') for b in ff.Basis.pauli(2)[1:]],
            skip_check=True,
            btype='Pauli')
        complete_basis = ff.Basis(qubit_subspace_basis,
                                  traceless=False,
                                  btype='Pauli')

        identifiers = ['eps_12', 'eps_23', 'eps_34', 'b_12', 'b_23', 'b_34']
        H_c = list(zip(c_opers, c_coeffs, identifiers))
        H_n = list(zip(n_opers, n_coeffs, identifiers))
        cnot = ff.PulseSequence(H_c, H_n, dt, basis=qubit_subspace_basis)
        cnot_full = ff.PulseSequence(H_c, H_n, dt, basis=complete_basis)

        # Manually set dimension of pulse as the dimension of the computational
        # subspace
        cnot.d = 4
        f_min = 1 / cnot.tau
        omega = np.geomspace(f_min, 1e2, 250)

        for A, alpha, MC in zip(A, (0.0, 0.7), infid_MC):
            S = A / omega**alpha

            infid, xi = ff.infidelity(cnot,
                                      S,
                                      omega,
                                      identifiers[:3],
                                      return_smallness=True)

            K = numeric.calculate_cumulant_function(cnot_full, S, omega,
                                                    identifiers[:3])
            infid_P = -np.trace(K[:, :16, :16], axis1=1, axis2=2).real / 4**2

            self.assertLessEqual(np.abs(1 - (infid.sum() / MC)), 0.10)
            self.assertLessEqual(np.abs(1 - (infid_P.sum() / MC)), 0.10)
            self.assertLessEqual(infid.sum(), xi**2 / 4)
    def test_concatenate_with_filter_function_SE12(self):
        """Concatenate two Spin Echos with both having a filter function."""
        tau = 10
        tau_pi = 1e-4
        omega = np.logspace(-1, 2, 500)
        n = 1

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

        H_n_SE = [[util.paulis[3], np.ones_like(dt_SE)]]
        SE_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 = [[util.paulis[3], np.ones_like(dt_CPMG)]]
        CPMG = ff.PulseSequence(H_c_CPMG, H_n_CPMG, dt_CPMG)

        SE_1.cache_filter_function(omega)
        SE_2.cache_filter_function(omega)
        CPMG.cache_filter_function(omega)

        CPMG_concat = SE_1 @ SE_2

        self.assertIsNotNone(SE_1._total_phases)
        self.assertIsNotNone(SE_1._total_Q)
        self.assertIsNotNone(SE_1._total_Q_liouville)
        self.assertIsNotNone(SE_2._total_phases)
        self.assertIsNotNone(SE_2._total_Q)
        self.assertIsNotNone(SE_2._total_Q_liouville)
        self.assertIsNotNone(CPMG._total_phases)
        self.assertIsNotNone(CPMG._total_Q)
        self.assertIsNotNone(CPMG._total_Q_liouville)
        self.assertIsNotNone(CPMG_concat._total_phases)
        self.assertIsNotNone(CPMG_concat._total_Q)
        self.assertIsNotNone(CPMG_concat._total_Q_liouville)

        self.assertEqual(CPMG_concat, CPMG)
        self.assertArrayAlmostEqual(CPMG_concat._F, CPMG._F, rtol=1e-11)
Exemple #8
0
    def test_filter_functions(self):

        # Basis for qubit subspace
        qubit_subspace_basis = ff.Basis(
            [np.pad(b, 1, 'constant') for b in ff.Basis.pauli(2)],
            skip_check=True,
            btype='Pauli')

        c_opers = ff_testutil.subspace_opers
        n_opers = c_opers
        c_coeffs, n_coeffs = ff_testutil.c_coeffs, ff_testutil.n_coeffs
        dt = ff_testutil.dt
        infid_MC = ff_testutil.cnot_infid_fast
        A = ff_testutil.A

        identifiers = ['eps_12', 'eps_23', 'eps_34', 'b_12', 'b_23', 'b_34']
        H_c = list(
            zip(c_opers[:3] + [c_opers[3] + 7 * c_opers[4] - c_opers[5]],
                c_coeffs[:3] + [c_coeffs[3]], identifiers[:4]))
        H_n = list(zip(n_opers[:3], n_coeffs[:3], identifiers[:3]))
        cnot = ff.PulseSequence(H_c, H_n, dt, basis=qubit_subspace_basis)

        T = dt.sum()
        omega = np.logspace(np.log10(1 / T), 2, 125)
        S_t, omega_t = ff.util.symmetrize_spectrum(A[0] / omega**0.0, omega)
        infid, xi = ff.infidelity(cnot,
                                  S_t,
                                  omega_t,
                                  identifiers[:3],
                                  return_smallness=True)
        # infid scaled with d = 6, but we actually have d = 4
        infid *= 1.5
        self.assertLessEqual(np.abs(1 - (infid.sum() / infid_MC[0])), .4)
        self.assertLessEqual(infid.sum(), xi**2 / 4)

        time_slot_comp_closed = SchroedingerSolver(
            h_drift=[OPERATORS['h_drift']] * len(dt),
            h_ctrl=OPERATORS['h_ctrl'],
            initial_state=OPERATORS['initial_state'],
            tau=list(dt),
            calculate_propagator_derivatives=True,
            exponential_method='spectral',
            is_skew_hermitian=True,
            transfer_function=id_tf,
            amplitude_function=exp_amp_func,
            filter_function_h_n=H_n,
            filter_function_basis=qubit_subspace_basis)
        time_slot_comp_closed.set_optimization_parameters(eps.T)

        ff_infid = OperatorFilterFunctionInfidelity(
            solver=time_slot_comp_closed,
            noise_power_spec_density=S_t,
            omega=omega_t)
        print(ff_infid.grad())
        np.testing.assert_array_almost_equal(infid, ff_infid.costs() * 1.5)
def create_sing_trip_pulse_seq(eps, dbz, *args):

    H_c = [[sigma_z, exchange_interaction(eps[0]), 'control1'],
           [sigma_x, dbz * np.ones(eps.shape[1]), 'drift']]

    H_n = [[sigma_z, deriv_exchange_interaction(eps[0])]]

    dt = time_step * np.ones(n_time_steps)

    pulse = ff.PulseSequence(H_c, H_n, dt)
    return pulse
    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)
Exemple #11
0
    def test_concatenate_4_spin_echos(self):
        """Concatenate four Spin Echos with a random one having a filter
        function
        """
        tau = 1
        tau_pi = 1e-4
        omega = np.logspace(-2, 1, 200)
        n = 1

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

        H_n_SE = [[util.paulis[3], np.ones_like(dt_SE)]]
        SE = [ff.PulseSequence(H_c_SE, H_n_SE, dt_SE) for _ in range(4)]

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

        H_n_CPMG = [[util.paulis[3], np.ones_like(dt_CPMG)]]
        CPMG = ff.PulseSequence(H_c_CPMG, H_n_CPMG, dt_CPMG)

        SE[rng.randint(0, len(SE)-1)].cache_filter_function(omega)
        CPMG.cache_filter_function(omega)

        CPMG_concat_1 = ff.concatenate(SE)
        # Clean up so that we start from one SE with cached filter_function again
        for se in SE:
            se.cleanup('all')

        SE[rng.randint(0, len(SE)-1)].cache_filter_function(omega)
        CPMG_concat_2 = SE[0] @ SE[1] @ SE[2] @ SE[3]

        self.assertEqual(CPMG, CPMG_concat_1)
        self.assertEqual(CPMG, CPMG_concat_2)
        self.assertArrayAlmostEqual(CPMG_concat_1._filter_function,
                                    CPMG._filter_function, rtol=1e-10)
        self.assertArrayAlmostEqual(CPMG_concat_2._filter_function,
                                    CPMG._filter_function, rtol=1e-10)
Exemple #12
0
def P_n_pulse(n, N: int = 4, tau: float = 1):
    Id = qt.qeye(2)
    H_c = []
    H_n = []
    for l in range(n+1, N+1):
        Z = [Id]*(N - 2)
        Z.insert(n-1, qt.sigmaz())
        Z.insert(l-1, qt.sigmaz())
        Z = qt.tensor(Z)
        identifier = ('I'*(n-1) + 'Z' + 'I'*(l - n - 1) + 'Z' + 'I'*(N - l))
        H_c.append([Z, [-np.pi/4*2**(n - l)/tau], identifier])
        H_n.append([Z/np.sqrt(Z.shape[0]), [1], identifier])

    return ff.PulseSequence(H_c, H_n, [tau])
def create_pulse_sequence(u_ctrl, u_drift, *args):
    # hacky hacky!
    if len(args):
        d = args[0]

    basis = ff.Basis.ggm(d)
    H_c = (list(
        zip(basis[1:len(u_ctrl) + 1], u_ctrl,
            [f'c{i}' for i in range(len(u_ctrl) + 1)])) + list(
                zip(basis[len(u_ctrl) + 1:], u_drift,
                    [f'd{i}' for i in range(d**2 - len(u_ctrl) + 1)])))
    H_n = (list(zip(basis[1:], np.ones((d**2 - 1, u_drift.shape[1])))))
    dt = np.full(u_ctrl.shape[-1], fill_value=0.32)

    return ff.PulseSequence(H_c, H_n, dt, basis=basis)
Exemple #14
0
def T_F_pulse(N: int = 4, tau: float = 1):
    Id = qt.qeye(2)
    if N == 1:
        T = Id
        H_c = [[Id, [0], 'I']]
        H_n = [[T/np.sqrt(T.shape[0]), [1], 'I']]
    else:
        H_c = []
        H_n = []
        T = [Id]*(N - 1)
        T.insert(0, qt.sigmaz())
        for k in range(1, N+1):
            H_c.append([qt.tensor(T[-k+1:] + T[:-k+1]),
                        [np.pi/4*(1 - 2**(k - N))/tau],
                        'I'*(k - 1) + 'Z' + 'I'*(N - k)])
            H_n.append([qt.tensor(T[-k+1:] + T[:-k+1])/np.sqrt(2**len(T)),
                        [1], 'I'*(k - 1) + 'Z' + 'I'*(N - k)])

    return ff.PulseSequence(H_c, H_n, [tau])
    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)
Exemple #16
0
def R_k_pulse(k, theta, phi, N: int = 4, tau: float = 1):
    Id = qt.qeye(2)
    if N == 1:
        X = qt.sigmax()
        Y = qt.sigmay()
    else:
        X = [Id]*(N - 1)
        Y = [Id]*(N - 1)
        X.insert(k, qt.sigmax())
        Y.insert(k, qt.sigmay())
        X = qt.tensor(X)
        Y = qt.tensor(Y)

    H_c = [[X, [theta/2/tau*np.cos(phi)], 'I'*k + 'X' + 'I'*(N - k - 1)],
           [Y, [theta/2/tau*np.sin(phi)], 'I'*k + 'Y' + 'I'*(N - k - 1)]]
    H_n = [[X/np.sqrt(X.shape[0]), [1], 'I'*k + 'X' + 'I'*(N - k - 1)],
           [Y/np.sqrt(Y.shape[0]), [1], 'I'*k + 'Y' + 'I'*(N - k - 1)]]
    dt = [tau]

    return ff.PulseSequence(H_c, H_n, dt)
    def test_5_pulse_CDD(self):
        """5-pulse CDD"""
        tau = np.pi
        tau_pi = 1e-9
        omega = np.logspace(0, 3, 100)
        omega = np.concatenate([-omega[::-1], omega])
        n = 3

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

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

        self.assertArrayAlmostEqual(F,
                                    analytic.CDD(omega * tau, n),
                                    atol=1e-10)
Exemple #18
0
    def test_pulse_correlation_filter_function(self):
        """
        Test calculation of pulse correlation filter function and control
        matrix.
        """
        X, Y, Z = util.paulis[1:]
        T = 1
        omega = np.linspace(-2e1, 2e1, 250)
        H_c, H_n, dt = dict(), dict(), dict()
        H_c['X'] = [[X, [np.pi/2/T]]]
        H_n['X'] = [[X, [1]],
                    [Y, [1]],
                    [Z, [1]]]
        dt['X'] = [T]
        H_c['Y'] = [[Y, [np.pi/4/T]]]
        H_n['Y'] = [[X, [1]],
                    [Y, [1]],
                    [Z, [1]]]
        dt['Y'] = [T]
        n_nops = 3

        # Check if an exception is raised if we want to calculate the PC-FF but
        # one pulse has different frequencies
        with self.assertRaises(ValueError):
            pulses = dict()
            for i, key in enumerate(('X', 'Y')):
                pulses[key] = ff.PulseSequence(H_c[key], H_n[key], dt[key])
                pulses[key].cache_filter_function(omega + i)

            ff.concatenate([pulses['X'], pulses['Y']],
                           calc_pulse_correlation_FF=True)

        # Get filter functions at same frequencies
        [pulse.cache_filter_function(omega) for pulse in pulses.values()]

        pulse_1 = pulses['X'] @ pulses['Y']
        pulse_2 = ff.concatenate([pulses['X'], pulses['Y']],
                                 calc_pulse_correlation_FF=True,
                                 which='fidelity')
        pulse_3 = ff.concatenate([pulses['X'], pulses['Y']],
                                 calc_pulse_correlation_FF=True,
                                 which='generalized')

        self.assertTrue(pulse_2.is_cached('control_matrix_pc'))
        self.assertTrue(pulse_2.is_cached('filter_function_pc'))
        self.assertTrue(pulse_3.is_cached('control_matrix_pc'))
        self.assertTrue(pulse_3.is_cached('filter_function_pc_gen'))

        # Check if the filter functions on the diagonals are real
        filter_function = pulse_2.get_pulse_correlation_filter_function()
        diag_1 = np.eye(2, dtype=bool)
        diag_2 = np.eye(3, dtype=bool)
        self.assertTrue(np.isreal(filter_function[diag_1][:, diag_2]).all())

        self.assertEqual(pulse_1, pulse_2)
        self.assertEqual(pulse_2.get_pulse_correlation_filter_function().shape,
                         (2, 2, n_nops, n_nops, len(omega)))
        self.assertArrayAlmostEqual(
            pulse_1.get_filter_function(omega),
            pulse_2.get_pulse_correlation_filter_function().sum((0, 1))
        )
        self.assertArrayAlmostEqual(pulse_1.get_filter_function(omega),
                                    pulse_2._filter_function)

        # Test the behavior of the pulse correlation control matrix
        with self.assertRaises(ValueError):
            # R wrong dimension
            numeric.calculate_pulse_correlation_filter_function(
                pulse_1._control_matrix)

        with self.assertRaises(util.CalculationError):
            # not calculated
            pulse_1.get_pulse_correlation_control_matrix()

        control_matrix_pc = pulse_2.get_pulse_correlation_control_matrix()
        self.assertArrayEqual(
            filter_function,
            numeric.calculate_pulse_correlation_filter_function(
                control_matrix_pc, 'fidelity'
            )
        )

        control_matrix_pc = pulse_3.get_pulse_correlation_control_matrix()
        filter_function = \
            pulse_3.get_pulse_correlation_filter_function(which='fidelity')
        self.assertArrayEqual(
            filter_function,
            numeric.calculate_pulse_correlation_filter_function(
                control_matrix_pc, 'fidelity'
            )
        )

        filter_function = \
            pulse_3.get_pulse_correlation_filter_function(which='generalized')
        self.assertArrayEqual(
            filter_function,
            numeric.calculate_pulse_correlation_filter_function(
                control_matrix_pc, 'generalized'
            )
        )

        # If for some reason filter_function_pc_xy is removed, check if
        # recovered from control_matrix_pc
        pulse_2._filter_function_pc = None
        pulse_3._filter_function_pc_gen = None

        control_matrix_pc = pulse_3.get_pulse_correlation_control_matrix()
        filter_function = \
            pulse_3.get_pulse_correlation_filter_function(which='fidelity')
        self.assertArrayEqual(
            filter_function,
            numeric.calculate_pulse_correlation_filter_function(
                control_matrix_pc, 'fidelity'
            )
        )

        filter_function = \
            pulse_3.get_pulse_correlation_filter_function(which='generalized')
        self.assertArrayEqual(
            filter_function,
            numeric.calculate_pulse_correlation_filter_function(
                control_matrix_pc, 'generalized'
            )
        )

        spectrum = omega**0*1e-2
        with self.assertRaises(util.CalculationError):
            infid_1 = ff.infidelity(pulse_1, spectrum, omega,
                                    which='correlations')

        with self.assertRaises(ValueError):
            infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='foobar')

        for _ in range(10):
            n_nops = rng.randint(1, 4)
            identifiers = sample(['B_0', 'B_1', 'B_2'], n_nops)

            infid_X = ff.infidelity(pulses['X'], spectrum, omega,
                                    which='total',
                                    n_oper_identifiers=identifiers)
            infid_Y = ff.infidelity(pulses['Y'], spectrum, omega,
                                    which='total',
                                    n_oper_identifiers=identifiers)
            infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='total',
                                    n_oper_identifiers=identifiers)
            infid_2 = ff.infidelity(pulse_2, spectrum, omega,
                                    which='correlations',
                                    n_oper_identifiers=identifiers)

            self.assertAlmostEqual(infid_1.sum(), infid_2.sum())
            self.assertArrayAlmostEqual(infid_X, infid_2[0, 0])
            self.assertArrayAlmostEqual(infid_Y, infid_2[1, 1])

        # Test function for correlated noise spectra
        spectrum = np.array([[1e-4/omega**2, 1e-4*np.exp(-omega**2)],
                             [1e-4*np.exp(-omega**2), 1e-4/omega**2]])
        infid_1 = ff.infidelity(pulse_1, spectrum, omega, which='total',
                                n_oper_identifiers=['B_0', 'B_2'])
        infid_2 = ff.infidelity(pulse_2, spectrum, omega, which='correlations',
                                n_oper_identifiers=['B_0', 'B_2'])

        self.assertAlmostEqual(infid_1.sum(), infid_2.sum())
        self.assertArrayAlmostEqual(infid_1, infid_2.sum(axis=(0, 1)))
Exemple #19
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))
Exemple #20
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))
Exemple #21
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')
Exemple #22
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))
Exemple #23
0
c_coeffs = {
    gate: [J[gate][0], B[gate][0] * np.ones(n_dt[gate])]
    for gate in gates
}
n_coeffs = {gate: np.ones((3, n_dt[gate])) for gate in gates}

# Add identity gate, choosing the X/2 operation on the right qubit
for gate in gates:
    H_c['optimized'][gate] = list(
        zip(ff.util.paulis[[1, 3]] / 2, c_coeffs[gate], ('X', 'Z')))
    H_n['optimized'][gate] = list(
        zip(ff.util.paulis[1:2] / 2, n_coeffs[gate], ('X', )))
# %% Set up PulseSequences
pulses = {
    p: {g: ff.PulseSequence(H_c[p][g], H_n[p][g], dt[p][g])
        for g in gates}
    for p in pulse_types
}

# %% Define some parameters
m_min = 1
m_max = 151
# sequence lengths
N_l = 21
lengths = np.round(np.linspace(m_min, m_max, N_l)).astype(int)
# no. of random sequences per length
N_G = 50

omega = np.geomspace(1e-2 / (7 * m_max * T), 1e2 / T, 301) * 2 * np.pi
Exemple #24
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)
Exemple #25
0
    def test_concatenate_split_cnot(self):
        """Split up cnot and concatenate the parts."""
        c_opers, c_coeffs, dt = (testutil.subspace_opers, testutil.c_coeffs,
                                 testutil.dt)
        n_opers = c_opers
        n_coeffs = testutil.n_coeffs

        H_c = list(zip(c_opers, c_coeffs))
        H_n = list(zip(n_opers, n_coeffs))
        omega = np.logspace(-2, 1, 200)

        cnot_whole = ff.PulseSequence(H_c, H_n, dt)

        cnot_sliced = [
            ff.PulseSequence(list(zip(c_opers, [c[:10] for c in c_coeffs])),
                             list(zip(n_opers, [n[:10] for n in n_coeffs])),
                             dt[:10]),
            ff.PulseSequence(list(zip(c_opers, [c[10:15] for c in c_coeffs])),
                             list(zip(n_opers, [n[10:15] for n in n_coeffs])),
                             dt[10:15]),
            ff.PulseSequence(list(zip(c_opers, [c[15:100] for c in c_coeffs])),
                             list(zip(n_opers, [n[15:100] for n in n_coeffs])),
                             dt[15:100]),
            ff.PulseSequence(list(zip(c_opers,
                                      [c[100:245] for c in c_coeffs])),
                             list(zip(n_opers,
                                      [n[100:245] for n in n_coeffs])),
                             dt[100:245]),
            ff.PulseSequence(list(zip(c_opers, [c[245:] for c in c_coeffs])),
                             list(zip(n_opers, [n[245:] for n in n_coeffs])),
                             dt[245:])
        ]

        cnot_concatenated = ff.concatenate(cnot_sliced)

        self.assertEqual(cnot_whole, cnot_concatenated)
        self.assertEqual(cnot_whole._filter_function,
                         cnot_concatenated._filter_function)

        cnot_concatenated.cache_filter_function(omega)
        cnot_whole.cache_filter_function(omega)

        self.assertEqual(cnot_whole, cnot_concatenated)
        self.assertArrayAlmostEqual(cnot_whole._filter_function,
                                    cnot_concatenated._filter_function)

        # Test concatenation if different child sequences have a filter
        # function already calculated
        cnot_sliced = [
            ff.PulseSequence(list(zip(c_opers, [c[:100] for c in c_coeffs])),
                             list(zip(n_opers, [n[:100] for n in n_coeffs])),
                             dt[:100]),
            ff.PulseSequence(list(zip(c_opers,
                                      [c[100:150] for c in c_coeffs])),
                             list(zip(n_opers,
                                      [n[100:150] for n in n_coeffs])),
                             dt[100:150]),
            ff.PulseSequence(list(zip(c_opers, [c[150:] for c in c_coeffs])),
                             list(zip(n_opers, [n[150:] for n in n_coeffs])),
                             dt[150:])
        ]

        atol = 1e-12
        rtol = 1e-10

        for slice_1, slice_2 in product(cnot_sliced, cnot_sliced):

            for cnot_slice in cnot_sliced:
                cnot_slice.cleanup('all')

            slice_1.cache_filter_function(omega)
            slice_2.cache_filter_function(omega)

            cnot_concatenated = ff.concatenate(cnot_sliced)

            self.assertArrayEqual(cnot_whole.omega, cnot_concatenated.omega)
            self.assertArrayAlmostEqual(cnot_whole._filter_function,
                                        cnot_concatenated._filter_function,
                                        rtol, atol)
T = 20
H_n = {}
H_c = {}
dt = {}
H_c['Id'] = [[qt.sigmax().full(), [0], 'X']]
H_n['Id'] = [[qt.sigmax().full(), [1], 'X'], [qt.sigmay().full(), [1], 'Y']]
dt['Id'] = [T]
H_c['X2'] = [[qt.sigmax().full(), [np.pi / 4 / T], 'X']]
H_n['X2'] = [[qt.sigmax().full(), [1], 'X'], [qt.sigmay().full(), [1], 'Y']]
dt['X2'] = [T]
H_c['Y2'] = [[qt.sigmay().full(), [np.pi / 4 / T], 'Y']]
H_n['Y2'] = [[qt.sigmax().full(), [1], 'X'], [qt.sigmay().full(), [1], 'Y']]
dt['Y2'] = [T]

# %% Set up PulseSequences
Id = ff.PulseSequence(H_c['Id'], H_n['Id'], dt['Id'])
X2 = ff.PulseSequence(H_c['X2'], H_n['X2'], dt['X2'])
Y2 = ff.PulseSequence(H_c['Y2'], H_n['Y2'], dt['Y2'])

# %% Define some parameters
m_min = 1
m_max = 151
# sequence lengths
N_l = 21
lengths = np.round(np.linspace(m_min, m_max, N_l)).astype(int)
# no. of random sequences per length
N_G = 50

omega = np.geomspace(1e-2 / (7 * m_max * T), 1e2 / T, 301) * 2 * np.pi

# %% Cache filter functions for primitive gates
Exemple #27
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'))
Exemple #28
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'))
Exemple #29
0
    def test_accuracy(self):
        ID, X, Y, Z = util.paulis
        XI = util.tensor(X, ID)
        IX = util.tensor(ID, X)
        XII = util.tensor(X, ID, ID)
        IXI = util.tensor(ID, X, ID)
        IIX = util.tensor(ID, ID, X)
        XIII = util.tensor(X, ID, ID, ID)
        IXII = util.tensor(ID, X, ID, ID)
        IIXI = util.tensor(ID, ID, X, ID)
        IIIX = util.tensor(ID, ID, ID, X)
        YI = util.tensor(Y, ID)
        IY = util.tensor(ID, Y)
        YII = util.tensor(Y, ID, ID)
        IYI = util.tensor(ID, Y, ID)
        IIY = util.tensor(ID, ID, Y)
        YIII = util.tensor(Y, ID, ID, ID)
        IYII = util.tensor(ID, Y, ID, ID)
        IIYI = util.tensor(ID, ID, Y, ID)
        IIIY = util.tensor(ID, ID, ID, Y)
        ZI = util.tensor(Z, ID)
        IZ = util.tensor(ID, Z)
        ZII = util.tensor(Z, ID, ID)
        IZI = util.tensor(ID, Z, ID)
        ZIII = util.tensor(Z, ID, ID, ID)
        IZII = util.tensor(ID, Z, ID, ID)
        IIZI = util.tensor(ID, ID, Z, ID)
        IIIZ = util.tensor(ID, ID, ID, Z)

        IIZ = util.tensor(ID, ID, Z)
        XXX = util.tensor(X, X, X)

        n_dt = 10
        coeffs = rng.standard_normal((3, n_dt))
        X_pulse = ff.PulseSequence(
            [[X, coeffs[0], 'X']],
            list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(1)
        )
        Y_pulse = ff.PulseSequence(
            [[Y, coeffs[1], 'Y']],
            list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(1)
        )
        Z_pulse = ff.PulseSequence(
            [[Z, coeffs[2], 'Z']],
            list(zip((X, Y, Z), np.ones((3, n_dt)), ('X', 'Y', 'Z'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(1)
        )
        XZ_pulse = ff.PulseSequence(
            [[XI, coeffs[0], 'XI'],
             [IZ, coeffs[2], 'IZ']],
            list(zip((XI, YI, ZI, IX, IY, IZ), np.ones((6, n_dt)),
                     ('XI', 'YI', 'ZI', 'IX', 'IY', 'IZ'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(2)
        )
        XYZ_pulse = ff.PulseSequence(
            [[XII, coeffs[0], 'XII'],
             [IYI, coeffs[1], 'IYI'],
             [IIZ, coeffs[2], 'IIZ']],
            list(zip((XII, YII, ZII, IIX, IIY, IIZ, IXI, IYI, IZI, XXX),
                     np.ones((10, n_dt)),
                     ('XII', 'YII', 'ZII', 'IIX', 'IIY', 'IIZ', 'IXI', 'IYI',
                      'IZI', 'XXX'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(3)
        )
        ZYX_pulse = ff.PulseSequence(
            [[IIX, coeffs[0], 'IIX'],
             [IYI, coeffs[1], 'IYI'],
             [ZII, coeffs[2], 'ZII']],
            list(zip((IIX, IIY, IIZ, XII, YII, ZII, IXI, IYI, IZI),
                     np.ones((9, n_dt)),
                     ('IIX', 'IIY', 'IIZ', 'XII', 'YII', 'ZII', 'IXI', 'IYI',
                      'IZI'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(3)
        )
        XZXZ_pulse = ff.PulseSequence(
            [[XIII, coeffs[0], 'XIII'],
             [IZII, coeffs[2], 'IZII'],
             [IIXI, coeffs[0], 'IIXI'],
             [IIIZ, coeffs[2], 'IIIZ']],
            list(zip((XIII, YIII, ZIII, IXII, IYII, IZII,
                      IIXI, IIYI, IIZI, IIIX, IIIY, IIIZ),
                     np.ones((12, n_dt)),
                     ('XIII', 'YIII', 'ZIII', 'IXII', 'IYII', 'IZII',
                      'IIXI', 'IIYI', 'IIZI', 'IIIX', 'IIIY', 'IIIZ'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(4)
        )
        XXZZ_pulse = ff.PulseSequence(
            [[XIII, coeffs[0], 'XIII'],
             [IIZI, coeffs[2], 'IIZI'],
             [IXII, coeffs[0], 'IXII'],
             [IIIZ, coeffs[2], 'IIIZ']],
            list(zip((XIII, YIII, ZIII, IIXI, IIYI, IIZI,
                      IXII, IYII, IZII, IIIX, IIIY, IIIZ),
                     np.ones((12, n_dt)),
                     ('XIII', 'YIII', 'ZIII', 'IIXI', 'IIYI', 'IIZI',
                      'IXII', 'IYII', 'IZII', 'IIIX', 'IIIY', 'IIIZ'))),
            np.ones(n_dt),
            basis=ff.Basis.pauli(4)
        )

        # Cache
        omega = ff.util.get_sample_frequencies(XYZ_pulse, n_samples=50)
        X_pulse.cache_filter_function(omega)
        Y_pulse.cache_filter_function(omega)
        Z_pulse.cache_filter_function(omega)
        XZ_pulse.cache_filter_function(omega)
        XYZ_pulse.cache_filter_function(omega)
        ZYX_pulse.cache_filter_function(omega)
        XZXZ_pulse.cache_filter_function(omega)
        XXZZ_pulse.cache_filter_function(omega)

        # Test that mapping a pulse to itself returns the pulse itself and
        # issues a warning
        with self.assertWarns(UserWarning):
            pulse = ff.extend([(X_pulse, 0)])
            self.assertIs(pulse, X_pulse)

        with self.assertWarns(UserWarning):
            pulse = ff.extend([(XZ_pulse, (0, 1))])
            self.assertIs(pulse, XZ_pulse)

        # Test mapping two single-qubit pulses to a two-qubit pulse
        XZ_pulse_ext = ff.extend([
            (X_pulse, 0, {'X': 'XI', 'Y': 'YI', 'Z': 'ZI'}),
            (Z_pulse, 1, {'X': 'IX', 'Y': 'IY', 'Z': 'IZ'})
        ])

        self.assertEqual(XZ_pulse, XZ_pulse_ext)
        self.assertCorrectDiagonalization(XZ_pulse_ext, atol=1e-14)
        self.assertArrayAlmostEqual(XZ_pulse._propagators,
                                    XZ_pulse_ext._propagators, atol=1e-10)
        self.assertArrayAlmostEqual(XZ_pulse._control_matrix,
                                    XZ_pulse_ext._control_matrix, atol=1e-9)
        self.assertArrayAlmostEqual(XZ_pulse._filter_function,
                                    XZ_pulse_ext._filter_function, atol=1e-9)

        # Test additional noise Hamiltonian
        add_H_n = list(zip((XXX,), np.ones((1, n_dt)), ['XXX']))
        XYZ_pulse_ext = ff.extend(
            [(XZ_pulse, (0, 2),
              {i: i[0] + 'I' + i[1] for i in XZ_pulse.n_oper_identifiers}),
             (Y_pulse, 1,
              {i: 'I' + i[0] + 'I' for i in Y_pulse.n_oper_identifiers})],
            additional_noise_Hamiltonian=add_H_n
        )

        self.assertEqual(XYZ_pulse, XYZ_pulse_ext)
        self.assertCorrectDiagonalization(XYZ_pulse_ext, atol=1e-14)
        self.assertArrayAlmostEqual(XYZ_pulse._propagators,
                                    XYZ_pulse_ext._propagators, atol=1e-10)
        self.assertArrayAlmostEqual(XYZ_pulse._control_matrix,
                                    XYZ_pulse_ext._control_matrix, atol=1e-9)
        self.assertArrayAlmostEqual(XYZ_pulse._filter_function,
                                    XYZ_pulse_ext._filter_function, atol=1e-9)

        # Test remapping a two-qubit pulse
        ZYX_pulse_ext = ff.extend(
            [(XZ_pulse, (2, 0),
              {i: i[1] + 'I' + i[0] for i in XZ_pulse.n_oper_identifiers}),
             (Y_pulse, 1,
              {i: 'I' + i[0] + 'I' for i in Y_pulse.n_oper_identifiers})],
        )

        self.assertEqual(ZYX_pulse, ZYX_pulse_ext)
        self.assertCorrectDiagonalization(ZYX_pulse_ext, atol=1e-14)
        self.assertArrayAlmostEqual(ZYX_pulse._propagators,
                                    ZYX_pulse_ext._propagators, atol=1e-10)
        self.assertArrayAlmostEqual(ZYX_pulse._control_matrix,
                                    ZYX_pulse_ext._control_matrix, atol=1e-9)
        self.assertArrayAlmostEqual(ZYX_pulse._filter_function,
                                    ZYX_pulse_ext._filter_function, atol=1e-9)

        XZXZ_pulse_ext = ff.extend([
            (XZ_pulse, (0, 1),
             {i: i + 'II' for i in XZ_pulse.n_oper_identifiers}),
            (XZ_pulse, (2, 3),
             {i: 'II' + i for i in XZ_pulse.n_oper_identifiers})
        ], cache_diagonalization=True)
        self.assertEqual(XZXZ_pulse, XZXZ_pulse_ext)
        self.assertCorrectDiagonalization(XZXZ_pulse_ext, atol=1e-14)
        self.assertArrayAlmostEqual(XZXZ_pulse._propagators,
                                    XZXZ_pulse_ext._propagators, atol=1e-10)
        self.assertArrayAlmostEqual(XZXZ_pulse._control_matrix,
                                    XZXZ_pulse_ext._control_matrix, atol=1e-9)
        self.assertArrayAlmostEqual(XZXZ_pulse._filter_function,
                                    XZXZ_pulse_ext._filter_function, atol=1e-8)

        XZXZ_pulse_ext = ff.extend([
            (XZ_pulse, (0, 1),
             {i: i + 'II' for i in XZ_pulse.n_oper_identifiers}),
            (XZ_pulse, (2, 3),
             {i: 'II' + i for i in XZ_pulse.n_oper_identifiers})
        ], cache_diagonalization=False)
        self.assertEqual(XZXZ_pulse, XZXZ_pulse_ext)
        self.assertArrayAlmostEqual(XZXZ_pulse._total_propagator,
                                    XZXZ_pulse_ext._total_propagator,
                                    atol=1e-10)

        # Test merging with overlapping qubit ranges
        XXZZ_pulse_ext = ff.extend([
            (XZ_pulse, (0, 2),
             {i: i[0] + 'I' + i[1] + 'I'
              for i in XZ_pulse.n_oper_identifiers}),
            (XZ_pulse, (1, 3),
             {i: 'I' + i[0] + 'I' + i[1]
              for i in XZ_pulse.n_oper_identifiers}),
        ])
        self.assertEqual(XXZZ_pulse, XXZZ_pulse_ext)
        self.assertCorrectDiagonalization(XXZZ_pulse_ext, atol=1e-14)
        self.assertArrayAlmostEqual(XXZZ_pulse._propagators,
                                    XXZZ_pulse_ext._propagators, atol=1e-10)
        self.assertArrayAlmostEqual(XXZZ_pulse._control_matrix,
                                    XXZZ_pulse_ext._control_matrix, atol=1e-10)
        self.assertArrayAlmostEqual(XXZZ_pulse._filter_function,
                                    XXZZ_pulse_ext._filter_function, atol=1e-8)
Exemple #30
0
    def test_different_n_opers(self):
        """Test behavior when concatenating with different n_opers."""
        for d, n_dt in zip(rng.randint(2, 5, 20),
                           rng.randint(1, 11, 20)):
            opers = testutil.rand_herm_traceless(d, 10)
            letters = np.array(sample(list(string.ascii_letters), 10))
            n_idx = sample(range(10), rng.randint(2, 5))
            c_idx = sample(range(10), rng.randint(2, 5))
            n_opers = opers[n_idx]
            c_opers = opers[c_idx]
            n_coeffs = np.ones((n_opers.shape[0], n_dt))
            n_coeffs *= np.abs(rng.standard_normal((n_opers.shape[0], 1)))
            c_coeffs = rng.standard_normal((c_opers.shape[0], n_dt))
            dt = np.abs(rng.standard_normal(n_dt))
            n_ids = np.array([''.join(l) for l in letters[n_idx]])
            c_ids = np.array([''.join(l) for l in letters[c_idx]])

            pulse_1 = ff.PulseSequence(list(zip(c_opers, c_coeffs, c_ids)),
                                       list(zip(n_opers, n_coeffs, n_ids)),
                                       dt)
            permutation = rng.permutation(range(n_opers.shape[0]))
            pulse_2 = ff.PulseSequence(list(zip(c_opers, c_coeffs, c_ids)),
                                       list(zip(n_opers[permutation],
                                                n_coeffs[permutation],
                                                n_ids[permutation])),
                                       dt)
            more_n_idx = sample(range(10), rng.randint(2, 5))
            more_n_opers = opers[more_n_idx]
            more_n_coeffs = np.ones((more_n_opers.shape[0], n_dt))
            more_n_coeffs *= np.abs(rng.standard_normal(
                (more_n_opers.shape[0], 1)))
            more_n_ids = np.array([''.join(l) for l in letters[more_n_idx]])
            pulse_3 = ff.PulseSequence(list(zip(c_opers, c_coeffs, c_ids)),
                                       list(zip(more_n_opers, more_n_coeffs,
                                                more_n_ids)),
                                       dt)

            nontrivial_n_coeffs = np.abs(rng.standard_normal(
                (n_opers.shape[0], n_dt)))
            pulse_4 = ff.PulseSequence(list(zip(c_opers, c_coeffs, c_ids)),
                                       list(zip(more_n_opers,
                                                nontrivial_n_coeffs,
                                                more_n_ids)),
                                       dt)

            omega = np.geomspace(.1, 10, 50)

            # Test caching
            with self.assertRaises(ValueError):
                ff.concatenate([pulse_1, pulse_3],
                               calc_filter_function=True)

            with self.assertRaises(ValueError):
                ff.concatenate([pulse_1, pulse_3],
                               calc_pulse_correlation_FF=True)

            pulse_1.cache_filter_function(omega)
            pulse_2.cache_filter_function(omega)
            pulse_3.cache_filter_function(omega)
            pulse_11 = ff.concatenate([pulse_1, pulse_1])
            pulse_12 = ff.concatenate([pulse_1, pulse_2])
            pulse_13_1 = ff.concatenate([pulse_1, pulse_3])
            pulse_13_2 = ff.concatenate([pulse_1, pulse_3],
                                        calc_filter_function=True)

            # concatenate pulses with different n_opers and nontrivial sens.
            subset = (set.issubset(set(pulse_1.n_oper_identifiers),
                                   set(pulse_4.n_oper_identifiers)) or
                      set.issubset(set(pulse_4.n_oper_identifiers),
                                   set(pulse_1.n_oper_identifiers)))

            if not subset and (len(pulse_1.dt) > 1 or len(pulse_4.dt) > 1):
                with self.assertRaises(ValueError):
                    pulse_1 @ pulse_4

            self.assertEqual(pulse_11, pulse_12)
            # Filter functions should be the same even though pulse_2 has
            # different n_oper ordering
            self.assertArrayAlmostEqual(pulse_11._control_matrix,
                                        pulse_12._control_matrix, atol=1e-12)
            self.assertArrayAlmostEqual(pulse_11._filter_function,
                                        pulse_12._filter_function, atol=1e-12)

            should_be_cached = False
            for i in n_idx:
                if i in more_n_idx:
                    should_be_cached = True
            self.assertEqual(should_be_cached,
                             pulse_13_1.is_cached('filter_function'))

            # Test forcibly caching
            self.assertTrue(pulse_13_2.is_cached('filter_function'))