def test_apply_errors(self):
        """Test that apply fails for incorrect state preparation"""
        self.logTestName()

        with self.assertRaisesRegex(
                ValueError, 'incorrect size for the number of subsystems'):
            p = [thermal_state(0.5)]
            self.dev.apply('GaussianState', wires=[0], par=[p])

        with self.assertRaisesRegex(ValueError,
                                    'Incorrect number of subsystems'):
            p = U
            self.dev.apply('Interferometer', wires=[0], par=[p])

        with self.assertRaisesRegex(
                ValueError,
                "Invalid target subsystems provided in 'wires' argument"):
            p = U2
            dev = DefaultGaussian(wires=4, shots=0, hbar=hbar)
            self.dev.apply('Interferometer', wires=[0, 1, 2], par=[p])
示例#2
0
 def setUp(self):
     self.dev = DefaultGaussian(wires=2, shots=0, hbar=hbar)
示例#3
0
class TestDefaultGaussianDevice(BaseTest):
    """Test the default gaussian device. The test ensures that the device is properly
    applying gaussian operations and calculating the correct observables."""
    def setUp(self):
        self.dev = DefaultGaussian(wires=2, shots=0, hbar=hbar)

    def test_operation_map(self):
        """Test that default Gaussian device supports all PennyLane Gaussian CV gates."""
        self.logTestName()

        non_supported = {
            'FockDensityMatrix', 'FockStateVector', 'FockState', 'CrossKerr',
            'CatState', 'CubicPhase', 'Kerr'
        }

        self.assertEqual(
            set(qml.ops._cv__ops__) - non_supported,
            set(self.dev._operation_map))

    def test_observable_map(self):
        """Test that default Gaussian device supports all PennyLane Gaussian continuous observables."""
        self.logTestName()
        self.assertEqual(
            set(qml.ops._cv__obs__) | {'Identity'} - {'Heterodyne'},
            set(self.dev._observable_map))

    def test_apply(self):
        """Test the application of gates to a state"""
        self.logTestName()

        # loop through all supported operations
        for gate_name, fn in self.dev._operation_map.items():
            log.debug("\tTesting %s gate...", gate_name)
            self.dev.reset()

            # start in the displaced squeezed state
            alpha = 0.542 + 0.123j
            a = abs(alpha)
            phi_a = np.angle(alpha)
            r = 0.652
            phi_r = -0.124

            self.dev.apply('DisplacedSqueezedState',
                           wires=[0],
                           par=[a, phi_a, r, phi_r])
            self.dev.apply('DisplacedSqueezedState',
                           wires=[1],
                           par=[a, phi_a, r, phi_r])

            # get the equivalent pennylane operation class
            op = qml.ops.__getattribute__(gate_name)
            # the list of wires to apply the operation to
            w = list(range(op.num_wires))

            if op.par_domain == 'A':
                # the parameter is an array
                if gate_name == 'GaussianState':
                    p = [
                        np.array([0.432, 0.123, 0.342, 0.123]),
                        np.diag([0.5234] * 4)
                    ]
                    w = list(range(2))
                    expected_out = p
                elif gate_name == 'Interferometer':
                    w = list(range(2))
                    p = [U]
                    S = fn(*p)
                    expected_out = S @ self.dev._state[0], S @ self.dev._state[
                        1] @ S.T
            else:
                # the parameter is a float
                p = [0.432423, -0.12312, 0.324, 0.751][:op.num_params]

                if gate_name == 'Displacement':
                    alpha = p[0] * np.exp(1j * p[1])
                    state = self.dev._state
                    mu = state[0].copy()
                    mu[w[0]] += alpha.real * np.sqrt(2 * hbar)
                    mu[w[0] + 2] += alpha.imag * np.sqrt(2 * hbar)
                    expected_out = mu, state[1]
                elif 'State' in gate_name:
                    mu, cov = fn(*p, hbar=hbar)
                    expected_out = self.dev._state
                    expected_out[0][[w[0], w[0] + 2]] = mu

                    ind = np.concatenate(
                        [np.array([w[0]]),
                         np.array([w[0]]) + 2])
                    rows = ind.reshape(-1, 1)
                    cols = ind.reshape(1, -1)
                    expected_out[1][rows, cols] = cov
                else:
                    # if the default.gaussian is an operation accepting parameters,
                    # initialise it using the parameters generated above.
                    S = fn(*p)

                    # calculate the expected output
                    if op.num_wires == 1:
                        # reorder from symmetric ordering to xp-ordering
                        S = block_diag(
                            S, np.identity(2))[:, [0, 2, 1, 3]][[0, 2, 1, 3]]

                    expected_out = S @ self.dev._state[0], S @ self.dev._state[
                        1] @ S.T

            self.dev.apply(gate_name, wires=w, par=p)

            # verify the device is now in the expected state
            self.assertAllAlmostEqual(self.dev._state[0],
                                      expected_out[0],
                                      delta=self.tol)
            self.assertAllAlmostEqual(self.dev._state[1],
                                      expected_out[1],
                                      delta=self.tol)

    def test_apply_errors(self):
        """Test that apply fails for incorrect state preparation"""
        self.logTestName()

        with self.assertRaisesRegex(
                ValueError, 'incorrect size for the number of subsystems'):
            p = [thermal_state(0.5)]
            self.dev.apply('GaussianState', wires=[0], par=[p])

        with self.assertRaisesRegex(ValueError,
                                    'Incorrect number of subsystems'):
            p = U
            self.dev.apply('Interferometer', wires=[0], par=[p])

        with self.assertRaisesRegex(
                ValueError,
                "Invalid target subsystems provided in 'wires' argument"):
            p = U2
            dev = DefaultGaussian(wires=4, shots=0, hbar=hbar)
            self.dev.apply('Interferometer', wires=[0, 1, 2], par=[p])

    def test_expectation(self):
        """Test that expectation values are calculated correctly"""
        self.logTestName()

        dev = qml.device('default.gaussian', wires=1, hbar=hbar)

        # test correct mean for <n> of a displaced thermal state
        nbar = 0.5431
        alpha = 0.324 - 0.59j
        dev.apply('ThermalState', wires=[0], par=[nbar])
        dev.apply('Displacement', wires=[0], par=[alpha, 0])
        mean = dev.expval('NumberOperator', [0], [])
        self.assertAlmostEqual(mean, np.abs(alpha)**2 + nbar, delta=self.tol)

        # test correct mean for Homodyne P measurement
        alpha = 0.324 - 0.59j
        dev.apply('CoherentState', wires=[0], par=[alpha])
        mean = dev.expval('P', [0], [])
        self.assertAlmostEqual(mean,
                               alpha.imag * np.sqrt(2 * hbar),
                               delta=self.tol)

        # test correct mean for Homodyne measurement
        mean = dev.expval('QuadOperator', [0], [np.pi / 2])
        self.assertAlmostEqual(mean,
                               alpha.imag * np.sqrt(2 * hbar),
                               delta=self.tol)

        # test correct mean for number state expectation |<n|alpha>|^2
        # on a coherent state
        for n in range(3):
            mean = dev.expval('FockStateProjector', [0], [np.array([n])])
            expected = np.abs(
                np.exp(-np.abs(alpha)**2 / 2) * alpha**n / np.sqrt(fac(n)))**2
            self.assertAlmostEqual(mean, expected, delta=self.tol)

        # test correct mean for number state expectation |<n|S(r)>|^2
        # on a squeezed state
        n = 1
        r = 0.4523
        dev.apply('SqueezedState', wires=[0], par=[r, 0])
        mean = dev.expval('FockStateProjector', [0], [np.array([2 * n])])
        expected = np.abs(
            np.sqrt(fac(2 * n)) / (2**n * fac(n)) * (-np.tanh(r))**n /
            np.sqrt(np.cosh(r)))**2
        self.assertAlmostEqual(mean, expected, delta=self.tol)

    def test_variance_displaced_thermal_mean_photon(self):
        """test correct variance for <n> of a displaced thermal state"""
        self.logTestName()
        dev = qml.device('default.gaussian', wires=1, hbar=hbar)

        nbar = 0.5431
        alpha = 0.324 - 0.59j
        dev.apply('ThermalState', wires=[0], par=[nbar])
        dev.apply('Displacement', wires=[0], par=[alpha, 0])
        var = dev.var('NumberOperator', [0], [])
        self.assertAlmostEqual(var,
                               nbar**2 + nbar + np.abs(alpha)**2 *
                               (1 + 2 * nbar),
                               delta=self.tol)

    def test_variance_coherent_homodyne(self):
        """test correct variance for Homodyne P measurement"""
        self.logTestName()
        dev = qml.device('default.gaussian', wires=1, hbar=hbar)

        alpha = 0.324 - 0.59j
        dev.apply('CoherentState', wires=[0], par=[alpha])
        var = dev.var('P', [0], [])
        self.assertAlmostEqual(var, hbar / 2, delta=self.tol)

        # test correct mean and variance for Homodyne measurement
        var = dev.var('QuadOperator', [0], [np.pi / 2])
        self.assertAlmostEqual(var, hbar / 2, delta=self.tol)

    def test_variance_coherent_numberstate(self):
        """test correct variance for number state expectation |<n|alpha>|^2
        on a coherent state
        """
        self.logTestName()
        dev = qml.device('default.gaussian', wires=1, hbar=hbar)

        alpha = 0.324 - 0.59j

        dev.apply('CoherentState', wires=[0], par=[alpha])

        for n in range(3):
            var = dev.var('FockStateProjector', [0], [np.array([n])])
            mean = np.abs(
                np.exp(-np.abs(alpha)**2 / 2) * alpha**n / np.sqrt(fac(n)))**2
            self.assertAlmostEqual(var, mean * (1 - mean), delta=self.tol)

    def test_variance_squeezed_numberstate(self):
        """test correct variance for number state expectation |<n|S(r)>|^2
        on a squeezed state
        """
        self.logTestName()
        dev = qml.device('default.gaussian', wires=1, hbar=hbar)

        n = 1
        r = 0.4523
        dev.apply('SqueezedState', wires=[0], par=[r, 0])
        var = dev.var('FockStateProjector', [0], [np.array([2 * n])])
        mean = np.abs(
            np.sqrt(fac(2 * n)) / (2**n * fac(n)) * (-np.tanh(r))**n /
            np.sqrt(np.cosh(r)))**2
        self.assertAlmostEqual(var, mean * (1 - mean), delta=self.tol)

    def test_reduced_state(self):
        """Test reduced state"""
        self.logTestName()

        # Test error is raised if requesting a non-existant subsystem
        with self.assertRaisesRegex(
                ValueError,
                "specified wires cannot be larger than the number of subsystems"
        ):
            self.dev.reduced_state([6, 4])

        # Test requesting via an integer
        res = self.dev.reduced_state(0)
        expected = self.dev.reduced_state([0])
        self.assertAllAlmostEqual(res[0], expected[0], delta=self.tol)
        self.assertAllAlmostEqual(res[1], expected[1], delta=self.tol)

        # Test requesting all wires returns the full state
        res = self.dev.reduced_state([0, 1])
        expected = self.dev._state
        self.assertAllAlmostEqual(res[0], expected[0], delta=self.tol)
        self.assertAllAlmostEqual(res[1], expected[1], delta=self.tol)
示例#4
0
 def setUp(self):
     self.dev = DefaultGaussian(wires=2,
                                shots=1000,
                                hbar=hbar,
                                analytic=True)