Exemplo n.º 1
0
    def test_calculate_decay_amplitudes(self):
        """Test raises of numeric.calculate_decay_amplitudes"""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)

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

        omega = rng.standard_normal(43)
        # single spectrum
        S = rng.standard_normal(78)
        for i in range(4):
            with self.assertRaises(ValueError):
                numeric.calculate_error_vector_correlation_functions(
                    pulse, np.tile(S, [1] * i), omega)
Exemplo n.º 3
0
    def test_oper_equiv(self):
        with self.assertRaises(ValueError):
            util.oper_equiv(rng.standard_normal((2, 2)),
                            rng.standard_normal((3, 3)))

        for d in rng.randint(2, 10, (5, )):
            psi = rng.standard_normal((d, 1)) + 1j * rng.standard_normal(
                (d, 1))
            # Also test broadcasting
            U = testutil.rand_herm(d, rng.randint(1, 11)).squeeze()
            phase = rng.standard_normal()

            result = util.oper_equiv(psi, psi * np.exp(1j * phase))
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], phase, places=5)

            result = util.oper_equiv(psi * np.exp(1j * phase), psi)
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], -phase, places=5)

            psi /= np.linalg.norm(psi, ord=2)

            result = util.oper_equiv(psi,
                                     psi * np.exp(1j * phase),
                                     normalized=True,
                                     eps=1e-13)
            self.assertTrue(result[0])
            self.assertArrayAlmostEqual(result[1], phase, atol=1e-5)

            result = util.oper_equiv(psi, psi + 1)
            self.assertFalse(result[0])

            result = util.oper_equiv(U, U * np.exp(1j * phase))
            self.assertTrue(np.all(result[0]))
            self.assertArrayAlmostEqual(result[1], phase, atol=1e-5)

            result = util.oper_equiv(U * np.exp(1j * phase), U)
            self.assertTrue(np.all(result[0]))
            self.assertArrayAlmostEqual(result[1], -phase, atol=1e-5)

            norm = np.sqrt(util.dot_HS(U, U))
            norm = norm[:, None, None] if U.ndim == 3 else norm
            U /= norm
            # TIP: In numpy 1.18 we could just do:
            # U /= np.expand_dims(np.sqrt(util.dot_HS(U, U)), axis=(-1, -2))
            result = util.oper_equiv(U,
                                     U * np.exp(1j * phase),
                                     normalized=True,
                                     eps=1e-10)
            self.assertTrue(np.all(result[0]))
            self.assertArrayAlmostEqual(result[1], phase)

            result = util.oper_equiv(U, U + 1)
            self.assertFalse(np.all(result[0]))
Exemplo n.º 4
0
    def test_integrate(self):
        f = rng.standard_normal(32)
        x = rng.random(32)
        self.assertEqual(util.integrate(f, x), np.trapz(f, x))

        f = rng.standard_normal((2, 32)).astype(complex)
        x = rng.random(32)
        self.assertArrayEqual(util.integrate(f, x), np.trapz(f, x))

        f = rng.standard_normal(32)
        x = np.linspace(0, 1, 32)
        dx = 1 / 31
        self.assertAlmostEqual(util.integrate(f, x), util.integrate(f, dx=dx))
Exemplo n.º 5
0
    def test_calculate_cumulant_function(self):
        """Test numeric.calculate_cumulant_function"""
        pulse = testutil.rand_pulse_sequence(2, 1, 1, 1)

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

        with self.assertRaises(ValueError):
            numeric.calculate_cumulant_function(pulse, None, None, None)
Exemplo n.º 6
0
    def test_basis_expansion_and_normalization(self):
        """Correct expansion of operators and normalization of bases"""
        for _ in range(10):
            d = rng.randint(2, 16)
            ggm_basis = ff.Basis.ggm(d)
            basis = ff.Basis(np.einsum('i,ijk->ijk', rng.standard_normal(d**2),
                                       ggm_basis),
                             skip_check=True)
            M = rng.standard_normal((d, d)) + 1j * rng.standard_normal((d, d))
            M -= np.trace(M) / d
            coeffs = ff.basis.expand(M, basis, normalized=False)
            self.assertArrayAlmostEqual(M, np.einsum('i,ijk', coeffs, basis))
            self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis),
                                        ff.basis.ggm_expand(M),
                                        atol=1e-14)
            self.assertArrayAlmostEqual(ff.basis.ggm_expand(M),
                                        ff.basis.ggm_expand(M, traceless=True),
                                        atol=1e-14)

            n = rng.randint(1, 50)
            M = (rng.standard_normal((n, d, d)) + 1j * rng.standard_normal(
                (n, d, d)))
            coeffs = ff.basis.expand(M, basis, normalized=False)
            self.assertArrayAlmostEqual(
                M, np.einsum('li,ijk->ljk', coeffs, basis))
            self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis),
                                        ff.basis.ggm_expand(M),
                                        atol=1e-14)

            # Argument to ggm_expand not square in last two dimensions
            with self.assertRaises(ValueError):
                ff.basis.ggm_expand(basis[..., 0])

            self.assertTrue(ff.basis.normalize(basis).isorthonorm)

            # Basis method and function should give the same
            normalized = ff.basis.normalize(basis)
            basis.normalize()
            self.assertEqual(normalized, basis)

            # normalize single element
            elem = basis[1]
            normalized = ff.basis.normalize(elem)
            elem.normalize()
            self.assertEqual(normalized, elem)

            # Not matrix or sequence of matrices
            with self.assertRaises(ValueError):
                ff.basis.normalize(basis[0, 0])
Exemplo n.º 7
0
    def test_oper_equiv(self):
        with self.assertRaises(ValueError):
            util.oper_equiv(*[np.ones((1, 2, 3))] * 2)

        for d in rng.randint(2, 10, (5, )):
            psi = rng.standard_normal((d, 1)) + 1j * rng.standard_normal(
                (d, 1))
            U = testutil.rand_herm(d).squeeze()
            phase = rng.standard_normal()

            result = util.oper_equiv(psi, psi * np.exp(1j * phase))
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], phase, places=5)

            result = util.oper_equiv(psi * np.exp(1j * phase), psi)
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], -phase, places=5)

            psi /= np.linalg.norm(psi, ord=2)

            result = util.oper_equiv(psi,
                                     psi * np.exp(1j * phase),
                                     normalized=True,
                                     eps=1e-13)
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], phase, places=5)

            result = util.oper_equiv(psi, psi + 1)
            self.assertFalse(result[0])

            result = util.oper_equiv(U, U * np.exp(1j * phase))
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], phase, places=5)

            result = util.oper_equiv(U * np.exp(1j * phase), U)
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], -phase, places=5)

            U /= np.sqrt(util.dot_HS(U, U))
            result = util.oper_equiv(U,
                                     U * np.exp(1j * phase),
                                     normalized=True,
                                     eps=1e-10)
            self.assertTrue(result[0])
            self.assertAlmostEqual(result[1], phase)

            result = util.oper_equiv(U, U + 1)
            self.assertFalse(result[0])
Exemplo n.º 8
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')
Exemplo n.º 9
0
    def test_basis_constructor(self):
        """Test the constructor for several failure modes"""

        # Constructing from given elements should check for __getitem__
        with self.assertRaises(TypeError):
            _ = ff.Basis(1)

        # All elements should be either sparse, Qobj, or ndarray
        elems = [
            ff.util.paulis[1],
            COO.from_numpy(ff.util.paulis[3]), [[0, 1], [1, 0]]
        ]
        with self.assertRaises(TypeError):
            _ = ff.Basis(elems)

        # Too many elements
        with self.assertRaises(ValueError):
            _ = ff.Basis(rng.standard_normal((5, 2, 2)))

        # Properly normalized
        self.assertEqual(ff.Basis.pauli(1), ff.Basis(ff.util.paulis))

        # Non traceless elems but traceless basis requested
        with self.assertRaises(ValueError):
            _ = ff.Basis(np.ones((2, 2)), traceless=True)

        # Calling with only the identity should work with traceless true or
        # false
        self.assertEqual(ff.Basis(np.eye(2), traceless=False),
                         ff.Basis(np.eye(2), traceless=True))

        # Constructing a basis from a basis should work
        _ = ff.Basis(ff.Basis.ggm(2)[1:])
Exemplo n.º 10
0
    def test_oper_equiv(self):
        self.assertFalse(
            util.oper_equiv(qutip.rand_ket(2), qutip.rand_dm(2))[0])

        for d in rng.integers(2, 10, (5, )):
            psi = qutip.rand_ket(d)
            U = qutip.rand_dm(d)
            phase = rng.standard_normal()

            result = util.oper_equiv(psi, psi * np.exp(1j * phase))
            self.assertTrue(result[0])
            self.assertAlmostEqual(np.mod(result[1], 2 * np.pi),
                                   np.mod(phase, 2 * np.pi),
                                   places=5)

            result = util.oper_equiv(psi * np.exp(1j * phase), psi)
            self.assertTrue(result[0])
            self.assertAlmostEqual(np.mod(result[1], 2 * np.pi),
                                   np.mod(-phase, 2 * np.pi),
                                   places=5)

            result = util.oper_equiv(U, U * np.exp(1j * phase))
            self.assertTrue(result[0])
            self.assertAlmostEqual(np.mod(result[1], 2 * np.pi),
                                   np.mod(phase, 2 * np.pi),
                                   places=5)

            result = util.oper_equiv(U * np.exp(1j * phase), U)
            self.assertTrue(result[0])
            self.assertAlmostEqual(np.mod(result[1], 2 * np.pi),
                                   np.mod(-phase, 2 * np.pi),
                                   places=5)
Exemplo n.º 11
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)
Exemplo n.º 12
0
    def test_tensor_transpose(self):
        # Test basic functionality
        paulis = np.array(util.paulis)
        I, X, Y, Z = paulis
        arr = util.tensor(I, X, Y, Z)
        arr_dims = [[2] * 4] * 2
        order = np.arange(4)

        for _ in range(20):
            order = rng.permutation(order)
            r = util.tensor_transpose(arr, order, arr_dims)
            self.assertArrayAlmostEqual(r, util.tensor(*paulis[order]))

        # Check exceptions
        with self.assertRaises(ValueError):
            # wrong arr_dims (too few dims)
            r = util.tensor_transpose(arr, order, [[2] * 3] * 2)

        with self.assertRaises(ValueError):
            # wrong arr_dims (too few dims)
            r = util.tensor_transpose(arr, order, [[2] * 4] * 1)

        with self.assertRaises(ValueError):
            # wrong arr_dims (dims too large)
            r = util.tensor_transpose(arr, order, [[3] * 4] * 2)

        with self.assertRaises(ValueError):
            # wrong order (too few axes)
            r = util.tensor_transpose(arr, (0, 1, 2), arr_dims)

        with self.assertRaises(ValueError):
            # wrong order (index 4 too large)
            r = util.tensor_transpose(arr, (1, 2, 3, 4), arr_dims)

        with self.assertRaises(ValueError):
            # wrong order (not unique axes)
            r = util.tensor_transpose(arr, (1, 1, 1, 1), arr_dims)

        with self.assertRaises(TypeError):
            # wrong order (floats instead of ints)
            r = util.tensor_transpose(arr, (0., 1., 2., 3.), arr_dims)

        # random tests
        for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10),
                                             rng.randint(3, 6, 10),
                                             rng.randint(1, 11, 10)):
            arrs = rng.standard_normal((n_args, n_broadcast, *[2] * rank))
            order = rng.permutation(n_args)
            arr_dims = [[2] * n_args] * rank

            r = util.tensor_transpose(util.tensor(*arrs, rank=rank),
                                      order=order,
                                      arr_dims=arr_dims,
                                      rank=rank)
            self.assertArrayAlmostEqual(r, util.tensor(*arrs[order],
                                                       rank=rank))
Exemplo n.º 13
0
    def test_cexp(self):
        """Fast complex exponential."""
        x = rng.standard_normal((50, 100))
        a = util.cexp(x)
        b = np.exp(1j * x)
        self.assertArrayAlmostEqual(a, b)

        a = util.cexp(-x)
        b = np.exp(-1j * x)
        self.assertArrayAlmostEqual(a, b)
Exemplo n.º 14
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)
Exemplo n.º 15
0
    def test_copy(self):
        pulse = testutil.rand_pulse_sequence(2, 2)
        old_copers = pulse.c_opers.copy()

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

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

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

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

        self.assertEqual(pulse, copied)
        self.assertNotEqual(pulse, deepcopied)
Exemplo n.º 16
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))
Exemplo n.º 17
0
    def test_tensor(self):
        shapes = [(1, 2, 3, 4, 5), (5, 4, 3, 2, 1)]
        A = rng.standard_normal(shapes[0])
        B = rng.standard_normal(shapes[1])
        with self.assertRaises(ValueError):
            util.tensor(A, B)

        shapes = [(3, 2, 1), (3, 4, 2)]
        A = rng.standard_normal(shapes[0])
        B = rng.standard_normal(shapes[1])
        with self.assertRaises(ValueError):
            util.tensor(A, B, rank=1)

        self.assertEqual(util.tensor(A, B, rank=2).shape, (3, 8, 2))
        self.assertEqual(util.tensor(A, B, rank=3).shape, (9, 8, 2))

        shapes = [(10, 1, 3, 2), (10, 1, 2, 3)]
        A = rng.standard_normal(shapes[0])
        B = rng.standard_normal(shapes[1])
        self.assertEqual(util.tensor(A, B).shape, (10, 1, 6, 6))

        shapes = [(3, 5, 4, 4), (3, 5, 4, 4)]
        A = rng.standard_normal(shapes[0])
        B = rng.standard_normal(shapes[1])
        self.assertEqual(util.tensor(A, B).shape, (3, 5, 16, 16))

        d = rng.randint(2, 9)
        eye = np.eye(d)
        for i in range(d):
            for j in range(d):
                A, B = eye[i:i + 1, :], eye[:, j:j + 1]
                self.assertArrayEqual(util.tensor(A, B, rank=1), np.kron(A, B))

        i, j = rng.randint(0, 4, (2, ))
        A, B = util.paulis[i], util.paulis[j]
        self.assertArrayEqual(util.tensor(A, B), np.kron(A, B))

        args = [
            rng.standard_normal((4, 1, 2)),
            rng.standard_normal((3, 2)),
            rng.standard_normal((4, 3, 5))
        ]
        self.assertEqual(util.tensor(*args, rank=1).shape, (4, 3, 20))
        self.assertEqual(util.tensor(*args, rank=2).shape, (4, 9, 20))
        self.assertEqual(util.tensor(*args, rank=3).shape, (16, 9, 20))

        args = [rng.standard_normal((2, 3, 4)), rng.standard_normal((4, 3))]
        with self.assertRaises(ValueError) as err:
            util.tensor(*args, rank=1)

        msg = ('Incompatible shapes (2, 3, 4) and (4, 3) for tensor ' +
               'product of rank 1.')
        self.assertEqual(msg, str(err.exception))
Exemplo n.º 18
0
    def test_infidelity(self):
        """Benchmark infidelity results against previous version's results"""
        rng = np.random.default_rng(seed=123456789)

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

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

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

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

                count += 1

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

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

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

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

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

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

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

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

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

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

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

        with self.assertRaises(NotImplementedError):
            # smallness parameter for correlated noise source
            ff.infidelity(pulse,
                          spectra[4](S0, omega),
                          omega,
                          n_oper_identifiers=['B_0', 'B_2'],
                          return_smallness=True)
Exemplo n.º 19
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')
Exemplo n.º 20
0
    def test_tensor_insert(self):
        I, X, Y, Z = util.paulis
        arr = util.tensor(X, I)

        with self.assertRaises(ValueError):
            # Test exception for empty args
            util.tensor_insert(arr, np.array([[]]), pos=0, arr_dims=[])

        r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=0)
        self.assertArrayAlmostEqual(r, util.tensor(Y, Z, X, I))

        r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=1)
        self.assertArrayAlmostEqual(r, util.tensor(X, Y, Z, I))

        r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=2)
        self.assertArrayAlmostEqual(r, util.tensor(X, I, Y, Z))

        # Test pos being negative
        r = util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=-1)
        self.assertArrayAlmostEqual(r, util.tensor(X, Y, Z, I))

        # Test pos exception
        with self.assertRaises(IndexError) as err:
            util.tensor_insert(arr, Y, Z, arr_dims=[[2, 2], [2, 2]], pos=3)

        msg = 'Invalid position 3 specified. Must be between -2 and 2.'
        self.assertEqual(msg, str(err.exception))

        # Test broadcasting and rank != 2
        A, B, C = (rng.standard_normal(
            (2, 3, 1, 2)), rng.standard_normal(
                (2, 3, 1, 2)), rng.standard_normal((3, 1, 3)))

        arr = util.tensor(A, C, rank=1)
        r = util.tensor_insert(arr, B, pos=1, rank=1, arr_dims=[[2, 3]])
        self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=1))

        # Test exceptions for wrong arr_dims format
        with self.assertRaises(ValueError):
            util.tensor_insert(arr,
                               B,
                               pos=1,
                               rank=1,
                               arr_dims=[[3, 3], [1, 2], [2, 1]])

        with self.assertRaises(ValueError):
            util.tensor_insert(arr, B, pos=1, rank=1, arr_dims=[[2], [2, 1]])

        A, B, C = (rng.standard_normal(
            (2, 3, 1, 2)), rng.standard_normal(
                (2, 3, 2, 2)), rng.standard_normal((3, 2, 1)))
        arr = util.tensor(A, C, rank=3)
        r = util.tensor_insert(arr,
                               B,
                               pos=1,
                               rank=3,
                               arr_dims=[[3, 3], [1, 2], [2, 1]])
        self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=3))

        # Test exceptions for wrong arr_dims format
        with self.assertRaises(ValueError):
            util.tensor_insert(arr,
                               B,
                               pos=1,
                               rank=3,
                               arr_dims=[[1, 2], [2, 1]])

        with self.assertRaises(ValueError):
            util.tensor_insert(arr,
                               B,
                               pos=1,
                               rank=2,
                               arr_dims=[[3, 3, 1], [1, 2], [2]])

        A, B, C = (rng.standard_normal((2, 1)), rng.standard_normal(
            (1, 2, 3)), rng.standard_normal(1))

        arr = util.tensor(A, C, rank=1)
        r = util.tensor_insert(arr, B, pos=0, rank=1, arr_dims=[[1, 1]])
        self.assertArrayAlmostEqual(r, util.tensor(A, B, C, rank=1))

        arrs, args = [
            rng.standard_normal((2, 2, 2)),
            rng.standard_normal((2, 2, 2))
        ]
        arr_dims = [[2, 2], [2, 2]]

        r = util.tensor_insert(util.tensor(*arrs),
                               *args,
                               pos=(0, 1),
                               arr_dims=arr_dims)
        self.assertArrayAlmostEqual(
            r, util.tensor(args[0], arrs[0], args[1], arrs[1]))

        r = util.tensor_insert(util.tensor(*arrs),
                               *args,
                               pos=(0, 0),
                               arr_dims=arr_dims)
        self.assertArrayAlmostEqual(r, util.tensor(*args, *arrs))

        r = util.tensor_insert(util.tensor(*arrs),
                               *args,
                               pos=(1, 2),
                               arr_dims=arr_dims)
        self.assertArrayAlmostEqual(
            r, util.tensor(*np.insert(arrs, (1, 2), args, axis=0)))

        # Test exception for wrong pos argument
        with self.assertRaises(ValueError):
            util.tensor_insert(util.tensor(*arrs),
                               *args,
                               pos=(0, 1, 2),
                               arr_dims=arr_dims)

        # Test exception for wrong shapes
        arrs, args = (rng.standard_normal(
            (2, 4, 3, 2)), rng.standard_normal((2, 2, 3, 4)))
        with self.assertRaises(ValueError) as err:
            util.tensor_insert(util.tensor(*arrs),
                               *args,
                               pos=(1, 2),
                               arr_dims=[[3, 3], [2, 2]])

        err_msg = ('Could not insert arg 0 with shape (4, 9, 4) into the ' +
                   'array with shape (2, 3, 4) at position 1.')
        cause_msg = ('Incompatible shapes (2, 3, 4) and (4, 9, 4) for ' +
                     'tensor product of rank 2.')

        self.assertEqual(err_msg, str(err.exception))
        self.assertEqual(cause_msg, str(err.exception.__cause__))

        # Do some random tests
        for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10),
                                             rng.randint(3, 6, 10),
                                             rng.randint(1, 11, 10)):
            arrs = rng.randn(n_args, n_broadcast, *[2] * rank)
            split_idx = rng.randint(1, n_args - 1)
            ins_idx = rng.randint(split_idx - n_args, n_args - split_idx)
            ins_arrs = arrs[:split_idx]
            arr = util.tensor(*arrs[split_idx:], rank=rank)
            sorted_arrs = np.insert(arrs[split_idx:],
                                    ins_idx,
                                    ins_arrs,
                                    axis=0)

            arr_dims = [[2] * (n_args - split_idx)] * rank
            r = util.tensor_insert(arr,
                                   *ins_arrs,
                                   pos=ins_idx,
                                   rank=rank,
                                   arr_dims=arr_dims)
            self.assertArrayAlmostEqual(r, util.tensor(*sorted_arrs,
                                                       rank=rank))

            pos = rng.randint(-split_idx + 1, split_idx, split_idx)
            r = util.tensor_insert(arr,
                                   *ins_arrs,
                                   pos=pos,
                                   rank=rank,
                                   arr_dims=arr_dims)
            sorted_arrs = np.insert(arrs[split_idx:], pos, ins_arrs, axis=0)
            self.assertArrayAlmostEqual(r,
                                        util.tensor(*sorted_arrs, rank=rank),
                                        atol=1e-10)
Exemplo n.º 21
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)
Exemplo n.º 22
0
 def test_abs2(self):
     x = rng.standard_normal((20, 100)) + 1j * rng.standard_normal(
         (20, 100))
     self.assertArrayAlmostEqual(np.abs(x)**2, util.abs2(x))
Exemplo n.º 23
0
    def test_tensor_merge(self):
        # Test basic functionality
        I, X, Y, Z = util.paulis
        arr = util.tensor(X, Y, Z)
        ins = util.tensor(I, I)
        r1 = util.tensor_merge(arr,
                               ins,
                               pos=[1, 2],
                               arr_dims=[[2] * 3, [2] * 3],
                               ins_dims=[[2] * 2, [2] * 2])
        r2 = util.tensor_merge(ins,
                               arr,
                               pos=[0, 1, 2],
                               arr_dims=[[2] * 2, [2] * 2],
                               ins_dims=[[2] * 3, [2] * 3])

        self.assertArrayAlmostEqual(r1, util.tensor(X, I, Y, I, Z))
        self.assertArrayAlmostEqual(r1, r2)

        # Test if tensor_merge and tensor_insert produce same results
        arr = util.tensor(Y, Z)
        ins = util.tensor(I, X)
        r1 = util.tensor_merge(arr,
                               ins,
                               pos=[0, 0],
                               arr_dims=[[2] * 2, [2] * 2],
                               ins_dims=[[2] * 2, [2] * 2])
        r2 = util.tensor_insert(arr,
                                I,
                                X,
                                pos=[0, 0],
                                arr_dims=[[2] * 2, [2] * 2])
        self.assertArrayAlmostEqual(r1, r2)

        # Test pos being negative
        r = util.tensor_merge(arr,
                              ins,
                              arr_dims=[[2, 2], [2, 2]],
                              ins_dims=[[2, 2], [2, 2]],
                              pos=(-1, -2))
        self.assertArrayAlmostEqual(r, util.tensor(X, Y, I, Z))

        # Test exceptions
        # Wrong dims format
        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 2], [2, 2], [2, 2]],
                              ins_dims=[[2, 2], [2, 2]])

        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 2], [2, 2]],
                              ins_dims=[[2, 2], [2, 2], [2, 2]])

        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 2], [2, 2, 2]],
                              ins_dims=[[2, 2], [2, 2]])

        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 2], [2, 2]],
                              ins_dims=[[2, 2], [2, 2, 2]])

        # Wrong pos
        with self.assertRaises(IndexError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 3),
                              arr_dims=[[2, 2], [2, 2]],
                              ins_dims=[[2, 2], [2, 2]])

        # Wrong dimensions given
        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 3], [2, 2]],
                              ins_dims=[[2, 2], [2, 2]])

        with self.assertRaises(ValueError):
            util.tensor_merge(arr,
                              ins,
                              pos=(1, 2),
                              arr_dims=[[2, 2], [2, 2]],
                              ins_dims=[[2, 3], [2, 2]])

        # Incompatible shapes
        arrs, args = (rng.standard_normal(
            (2, 4, 3, 2)), rng.standard_normal((2, 2, 3, 4)))
        with self.assertRaises(ValueError) as err:
            util.tensor_merge(util.tensor(*arrs),
                              util.tensor(*args),
                              pos=(1, 2),
                              arr_dims=[[3, 3], [2, 2]],
                              ins_dims=[[3, 3], [4, 4]])

        msg = ('Incompatible shapes (2, 9, 16) and (4, 9, 4) for tensor ' +
               'product of rank 2.')

        self.assertEqual(msg, str(err.exception))

        # Test rank 1 and broadcasting
        arr = rng.standard_normal((2, 10, 3, 4))
        ins = rng.standard_normal((2, 10, 3, 2))
        r = util.tensor_merge(util.tensor(*arr, rank=1),
                              util.tensor(*ins, rank=1),
                              pos=[0, 1],
                              arr_dims=[[4, 4]],
                              ins_dims=[[2, 2]],
                              rank=1)
        self.assertArrayAlmostEqual(
            r, util.tensor(ins[0], arr[0], ins[1], arr[1], rank=1))

        # Do some random tests
        for rank, n_args, n_broadcast in zip(rng.randint(1, 4, 10),
                                             rng.randint(3, 6, 10),
                                             rng.randint(1, 11, 10)):
            arrs = rng.standard_normal((n_args, n_broadcast, *[2] * rank))
            split_idx = rng.randint(1, n_args - 1)
            arr = util.tensor(*arrs[split_idx:], rank=rank)
            ins = util.tensor(*arrs[:split_idx], rank=rank)
            pos = rng.randint(0, split_idx, split_idx)
            sorted_arrs = np.insert(arrs[split_idx:],
                                    pos,
                                    arrs[:split_idx],
                                    axis=0)

            arr_dims = [[2] * (n_args - split_idx)] * rank
            ins_dims = [[2] * split_idx] * rank
            r = util.tensor_merge(arr,
                                  ins,
                                  pos=pos,
                                  rank=rank,
                                  arr_dims=arr_dims,
                                  ins_dims=ins_dims)
            self.assertArrayAlmostEqual(r, util.tensor(*sorted_arrs,
                                                       rank=rank))
Exemplo n.º 24
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))
Exemplo n.º 25
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))
Exemplo n.º 26
0
    def test_infidelity(self):
        """Benchmark infidelity results against previous version's results"""
        rng.seed(123456789)

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

        ref_infids = ([[0.415494970094, 0.89587362496],
                       [0.493004378474, 0.812378971328],
                       [0.133466914361, 0.197411969384],
                       [0.415494970094, 0.812378971328],
                       [[0.493004378474, 0.435140425045],
                        [0.435140425045, 0.812378971328]],
                       [3.62995021962, 2.938710386281],
                       [2.302617869945, 2.6187737025],
                       [0.506821680978, 0.695495602872],
                       [3.62995021962, 2.6187737025],
                       [[2.302617869945, 0.58515469294],
                        [0.58515469294, 2.6187737025]],
                       [2.822636459567, 1.205901937127],
                       [1.63758822101, 1.236844976323],
                       [0.324175447082, 0.329789052239],
                       [2.822636459567, 1.236844976323],
                       [[1.63758822101, 0.72007826813],
                        [0.72007826813, 1.236844976323]]])

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

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

                    # Infidelity matrix should be hermitian
                    self.assertArrayEqual(infids, infids.conj().T)

                count += 1

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

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

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

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

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

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

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

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

        with self.assertRaises(NotImplementedError):
            # smallness parameter for correlated noise source
            ff.infidelity(pulse,
                          spectra[4](S0, omega),
                          omega,
                          n_oper_identifiers=['B_0', 'B_2'],
                          return_smallness=True)
Exemplo n.º 27
0
    def test_basis_constructor(self):
        """Test the constructor for several failure modes"""
        # Constructing from given elements should check for __getitem__
        with self.assertRaises(TypeError):
            _ = ff.Basis(1)

        # All elements should be either sparse, Qobj, or ndarray
        elems = [
            util.paulis[1],
            COO.from_numpy(util.paulis[3]), [[0, 1], [1, 0]]
        ]
        with self.assertRaises(TypeError):
            _ = ff.Basis(elems)

        # Too many elements
        with self.assertRaises(ValueError):
            _ = ff.Basis(rng.standard_normal((5, 2, 2)))

        # Non traceless elems but traceless basis requested
        with self.assertRaises(ValueError):
            _ = ff.Basis.from_partial(np.ones((2, 2)), traceless=True)

        # Incorrect number of labels for default constructor
        with self.assertRaises(ValueError):
            _ = ff.Basis(util.paulis, labels=['a', 'b', 'c'])

        # Incorrect number of labels for from_partial constructor
        with self.assertRaises(ValueError):
            _ = ff.Basis.from_partial(util.paulis[:2], labels=['a', 'b', 'c'])

        # from_partial constructor should move identity label to the front
        basis = ff.Basis.from_partial([util.paulis[1], util.paulis[0]],
                                      labels=['x', 'i'])
        self.assertEqual(basis.labels[:2], ['i', 'x'])
        self.assertEqual(basis.labels[2:], ['$C_{2}$', '$C_{3}$'])

        # from_partial constructor should copy labels if it can
        partial_basis = ff.Basis.pauli(1)[[1, 3]]
        partial_basis.labels = [
            partial_basis.labels[1], partial_basis.labels[3]
        ]
        basis = ff.Basis.from_partial(partial_basis)
        self.assertEqual(basis.labels[:2], partial_basis.labels)
        self.assertEqual(basis.labels[2:], ['$C_{2}$', '$C_{3}$'])

        # Default constructor should return 3d array also for single 2d element
        basis = ff.Basis(rng.standard_normal((2, 2)))
        self.assertEqual(basis.shape, (1, 2, 2))

        # from_partial constructor should return same basis for 2d or 3d input
        elems = testutil.rand_herm(3)
        basis1 = ff.Basis.from_partial(elems, labels=['weif'])
        basis2 = ff.Basis.from_partial(elems.squeeze(), labels=['weif'])
        self.assertEqual(basis1, basis2)

        # Calling with only the identity should work with traceless true or false
        self.assertEqual(ff.Basis(np.eye(2), traceless=False),
                         ff.Basis(np.eye(2), traceless=True))

        # Constructing a basis from a basis should work
        _ = ff.Basis(ff.Basis.ggm(2)[1:])

        # Constructing should not change the elements
        elems = rng.standard_normal((6, 3, 3))
        basis = ff.Basis(elems)
        self.assertArrayEqual(elems, basis)
Exemplo n.º 28
0
    def test_basis_expansion_and_normalization(self):
        """Correct expansion of operators and normalization of bases"""
        # dtype
        b = ff.Basis.ggm(3)
        r = ff.basis.expand(rng.standard_normal((3, 3)), b, hermitian=False)
        self.assertTrue(r.dtype == 'complex128')
        r = ff.basis.expand(testutil.rand_herm(3), b, hermitian=True)
        self.assertTrue(r.dtype == 'float64')
        b._isherm = False
        r = ff.basis.expand(testutil.rand_herm(3), b, hermitian=True)
        self.assertTrue(r.dtype == 'complex128')

        r = ff.basis.ggm_expand(testutil.rand_herm(3), hermitian=True)
        self.assertTrue(r.dtype == 'float64')
        r = ff.basis.ggm_expand(rng.standard_normal((3, 3)), hermitian=False)
        self.assertTrue(r.dtype == 'complex128')

        for _ in range(10):
            d = rng.integers(2, 16)
            ggm_basis = ff.Basis.ggm(d)
            basis = ff.Basis(
                np.einsum('i,ijk->ijk', rng.standard_normal(d**2), ggm_basis))
            M = rng.standard_normal((d, d)) + 1j * rng.standard_normal((d, d))
            M -= np.trace(M) / d
            coeffs = ff.basis.expand(M, basis, normalized=False)
            self.assertArrayAlmostEqual(M, np.einsum('i,ijk', coeffs, basis))
            self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis),
                                        ff.basis.ggm_expand(M),
                                        atol=1e-14)
            self.assertArrayAlmostEqual(ff.basis.ggm_expand(M),
                                        ff.basis.ggm_expand(M, traceless=True),
                                        atol=1e-14)

            n = rng.integers(1, 50)
            M = rng.standard_normal((n, d, d)) + 1j * rng.standard_normal(
                (n, d, d))
            coeffs = ff.basis.expand(M, basis, normalized=False)
            self.assertArrayAlmostEqual(
                M, np.einsum('li,ijk->ljk', coeffs, basis))
            self.assertArrayAlmostEqual(ff.basis.expand(M, ggm_basis),
                                        ff.basis.ggm_expand(M),
                                        atol=1e-14)

            # Argument to ggm_expand not square in last two dimensions
            with self.assertRaises(ValueError):
                ff.basis.ggm_expand(basis[..., 0])

            self.assertTrue(ff.basis.normalize(basis).isorthonorm)

            # Basis method and function should give the same
            normalized = ff.basis.normalize(basis)
            basis.normalize()
            self.assertEqual(normalized, basis)

            # normalize single element
            elem = basis[1]
            normalized = ff.basis.normalize(elem)
            elem.normalize()
            self.assertEqual(normalized, elem)

            # Not matrix or sequence of matrices
            with self.assertRaises(ValueError):
                ff.basis.normalize(basis[0, 0])

            # Test copy
            arr = rng.standard_normal((3, 2, 2))
            basis = ff.Basis(arr)
            normalized = basis.normalize(copy=True)
            self.assertIsNot(normalized, basis)
            self.assertFalse(np.array_equal(normalized, basis))
            basis.normalize()
            self.assertArrayEqual(normalized, basis)
Exemplo n.º 29
0
 def test_mdot(self):
     arr = rng.standard_normal((3, 2, 4, 4))
     self.assertArrayEqual(util.mdot(arr, 0), arr[0] @ arr[1] @ arr[2])
     self.assertArrayEqual(util.mdot(arr, 1), arr[:, 0] @ arr[:, 1])
Exemplo n.º 30
0
    def test_infidelity(self):
        """Benchmark infidelity results against previous version's results"""
        rng.seed(123456789)

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

        ref_infids = ([0.448468950307,
                       0.941871479562], [0.65826575772, 1.042914346335],
                      [0.163303005479,
                       0.239032549377], [0.448468950307, 1.042914346335],
                      [[0.65826575772, 0.069510589685 + 0.069510589685j],
                       [0.069510589685 - 0.069510589685j,
                        1.042914346335]], [3.687399348243, 3.034914820757],
                      [2.590545568435,
                       3.10093804628], [0.55880380219, 0.782544974968
                                        ], [3.687399348243, 3.10093804628],
                      [[2.590545568435, -0.114514760108 - 0.114514760108j],
                       [-0.114514760108 + 0.114514760108j,
                        3.10093804628]], [2.864567451344, 1.270260393902], [
                            1.847740998731, 1.559401345443
                        ], [0.362116177417,
                            0.388022992097], [2.864567451344, 1.559401345443],
                      [[1.847740998731, 0.088373663409 + 0.088373663409j],
                       [0.088373663409 - 0.088373663409j, 1.559401345443]])

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

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

                    # Infidelity matrix should be hermitian
                    self.assertArrayEqual(infids, infids.conj().T)

                count += 1

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

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

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

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

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

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

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

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

        with self.assertRaises(NotImplementedError):
            # smallness parameter for correlated noise source
            ff.infidelity(pulse,
                          spectra[4](S0, omega),
                          omega,
                          n_oper_identifiers=['B_0', 'B_2'],
                          return_smallness=True)