Example #1
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))
Example #2
0
data_path = Path(__file__).parent.parent / 'examples/data'
struct = io.loadmat(str(data_path / 'CNOT.mat'))
eps = np.asarray(struct['eps'], order='C')
dt = np.asarray(struct['t'].ravel(), order='C')
B = np.asarray(struct['B'].ravel(), order='C')
B_avg = struct['BAvg'].ravel()
cnot_infid_fast = struct['infid_fast'].ravel()

J = np.exp(eps)
n_dt = len(dt)

d = 16
H = np.empty((6, d, d), dtype=float)
Id, Px, Py, Pz = util.paulis
# Exchange Hamiltonians
H[0] = 1 / 4 * sum(util.tensor(P, P, Id, Id) for P in (Px, Py, Pz)).real
H[1] = 1 / 4 * sum(util.tensor(Id, P, P, Id) for P in (Px, Py, Pz)).real
H[2] = 1 / 4 * sum(util.tensor(Id, Id, P, P) for P in (Px, Py, Pz)).real
# Zeeman Hamiltonians
H[3] = 1 / 8 * (util.tensor(Pz, Id, Id, Id) *
                (-3) + util.tensor(Id, Pz, Id, Id) +
                util.tensor(Id, Id, Pz, Id) + util.tensor(Id, Id, Id, Pz)).real
H[4] = 1 / 4 * (util.tensor(Pz, Id, Id, Id) *
                (-1) + util.tensor(Id, Pz, Id, Id) * (-1) +
                util.tensor(Id, Id, Pz, Id) + util.tensor(Id, Id, Id, Pz)).real
H[5] = 1 / 8 * (util.tensor(Pz, Id, Id, Id) *
                (-1) + util.tensor(Id, Pz, Id, Id) *
                (-1) + util.tensor(Id, Id, Pz, Id) *
                (-1) + util.tensor(Id, Id, Id, Pz) * 3).real
# Mean Magnetic field
H0 = B_avg / 2 * sum(
Example #3
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))
Example #4
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))
Example #5
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)
Example #6
0
    def test_exceptions(self):
        X = util.paulis[1]
        n_dt = 10
        omega = np.linspace(0, 1, 50)

        pulse_1 = testutil.rand_pulse_sequence(2, n_dt, btype='Pauli')
        pulse_2 = testutil.rand_pulse_sequence(2, n_dt, btype='GGM')

        pulse_1.cache_filter_function(omega)
        pulse_11 = ff.extend([[pulse_1, 0], [pulse_1, 1]])
        pulse_11.cache_filter_function(omega+1)

        with self.assertRaises(ValueError):
            # qubit indices don't match on pulse that is remapped
            ff.extend([(pulse_11, (2, 1, 0))])

        with self.assertRaises(ValueError):
            # wrong dimensions
            ff.extend([(pulse_1, (0, 1))])

        with self.assertRaises(ValueError):
            # wrong dimensions
            ff.extend([(pulse_1, (0,))], d_per_qubit=3)

        with self.assertRaises(ValueError):
            # wrong dimensions
            ff.extend([(pulse_11, (0,))])

        with self.assertRaises(ValueError):
            # different dt
            ff.extend([(pulse_1, 0), [pulse_2, 1]])

        with self.assertRaises(ValueError):
            # Multiple pulses mapped to same qubit
            ff.extend([(pulse_1, 0), [pulse_1, 0]])

        with self.assertRaises(ValueError):
            # N < max(qubits)
            ff.extend([(pulse_1, 2)], N=2)

        with self.assertRaises(ValueError):
            # cache_filter_function == True and unequal omega
            ff.extend([(pulse_1, 0), (pulse_11, (1, 2))],
                      cache_filter_function=True, omega=None)

        with self.assertRaises(ValueError):
            # cache_diagonalization == False and additional_noise_Hamiltonian
            # is not None
            additional_noise_Hamiltonian = [[util.tensor(X, X), np.ones(n_dt)]]
            ff.extend(
                [(pulse_1, 0), (pulse_1, 1)], cache_diagonalization=False,
                additional_noise_Hamiltonian=additional_noise_Hamiltonian
            )

        with self.assertRaises(ValueError):
            # additional noise Hamiltonian defines existing identifier
            additional_noise_Hamiltonian = [
                [util.tensor(X, X), np.ones(n_dt), 'foo'],
                [util.tensor(X, X), np.ones(n_dt), 'foo'],
            ]
            ff.extend(
                [(pulse_1, 0), (pulse_1, 1)],
                additional_noise_Hamiltonian=additional_noise_Hamiltonian
            )

        with self.assertRaises(ValueError):
            # additional_noise_Hamiltonian has wrong dimensions
            additional_noise_Hamiltonian = [[util.tensor(X, X, X),
                                             np.ones(n_dt)]]
            ff.extend(
                [(pulse_1, 0), (pulse_1, 1)],
                additional_noise_Hamiltonian=additional_noise_Hamiltonian
            )

        with self.assertWarns(UserWarning):
            # Non-pauli basis
            ff.extend([(pulse_2, 0)])
Example #7
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)
Example #8
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')
Example #9
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)