def test_variance(self):
        """If the variance of the observable is first order, then
        parameter-shift is supported. If the observable is second order,
        however, only finite-differences is supported."""

        with qml.tape.JacobianTape() as tape:
            qml.Rotation(1.0, wires=[0])
            qml.var(qml.P(0))  # first order

        assert _grad_method(tape, 0) == "A"

        with qml.tape.JacobianTape() as tape:
            qml.Rotation(1.0, wires=[0])
            qml.var(qml.NumberOperator(0))  # second order

        assert _grad_method(tape, 0) == "F"

        with qml.tape.JacobianTape() as tape:
            qml.Rotation(1.0, wires=[0])
            qml.Rotation(1.0, wires=[1])
            qml.Beamsplitter(0.5, 0.0, wires=[0, 1])
            qml.var(qml.NumberOperator(0))  # fourth order
            qml.expval(qml.NumberOperator(1))

        assert _grad_method(tape, 0) == "F"
        assert _grad_method(tape, 1) == "F"
        assert _grad_method(tape, 2) == "F"
        assert _grad_method(tape, 3) == "F"
Example #2
0
 def circuit(x=None):
     qml.DisplacementEmbedding(features=x, wires=range(n_wires), method="phase", c=1.0)
     qml.Beamsplitter(np.pi / 2, 0, wires=[0, 1])
     qml.DisplacementEmbedding(features=[0, 0], wires=range(n_wires), method="phase", c=1.0)
     return [
         qml.expval(qml.NumberOperator(wires=0)),
         qml.expval(qml.NumberOperator(wires=1)),
     ]
 def circuit(x=None):
     qml.templates.DisplacementEmbedding(
         features=x, wires=range(n_wires), method="amplitude", c=1.0
     )
     return [
         qml.expval(qml.NumberOperator(wires=0)),
         qml.expval(qml.NumberOperator(wires=1)),
     ]
Example #4
0
 def circuit(x=None):
     SqueezingEmbedding(features=x,
                        wires=range(n_wires),
                        method='amplitude',
                        c=1)
     return [
         qml.expval(qml.NumberOperator(wires=0)),
         qml.expval(qml.NumberOperator(wires=1))
     ]
Example #5
0
 def circuit(x=None):
     SqueezingEmbedding(features=x,
                        wires=range(n_wires),
                        method='phase',
                        c=1)
     Beamsplitter(pi / 2, 0, wires=[0, 1])
     SqueezingEmbedding(features=[0, 0],
                        wires=range(n_wires),
                        method='phase',
                        c=1)
     return [
         qml.expval(qml.NumberOperator(wires=0)),
         qml.expval(qml.NumberOperator(wires=1))
     ]
 def circuit(varphi, mesh=None):
     qml.Interferometer(theta=[0.21],
                        phi=[0.53],
                        varphi=varphi,
                        mesh=mesh,
                        wires=[0, 1])
     return qml.expval(qml.NumberOperator(0))
Example #7
0
    def test_device_wire_expansion(self, tol):
        """Test that the transformation works correctly
        for the case where the transformation applies to more wires
        than the observable."""

        # create a 3-mode symmetric transformation
        wires = qml.wires.Wires([0, "a", 2])
        ndim = 1 + 2 * len(wires)

        Z = np.arange(ndim**2).reshape(ndim, ndim)
        Z = Z.T + Z

        obs = qml.NumberOperator(0)
        res = CVParamShiftTape._transform_observable(obs,
                                                     Z,
                                                     device_wires=wires)

        # The Heisenberg representation of the number operator
        # is (X^2 + P^2) / (2*hbar) - 1/2. We use the ordering
        # I, X0, Xa, X2, P0, Pa, P2.
        A = np.diag([-0.5, 0.25, 0.25, 0, 0, 0, 0])
        expected = A @ Z + Z @ A

        assert isinstance(res, qml.PolyXP)
        assert res.wires == wires
        assert np.allclose(res.data[0], expected, atol=tol, rtol=0)
Example #8
0
 def circuit(varphi, bs=None):
     Interferometer(theta=[],
                    phi=[],
                    varphi=varphi,
                    beamsplitter=bs,
                    wires=0)
     return qml.expval(qml.NumberOperator(0))
Example #9
0
 def circuit(varphi, mesh):
     Interferometer(theta=None,
                    phi=None,
                    varphi=varphi,
                    mesh=mesh,
                    wires=0)
     return qml.expval(qml.NumberOperator(0))
Example #10
0
 def circuit(params):
     for i in range(num_wires):
         qml.Squeezing(params[i], 0, wires=i)
     return [
         qml.expval(qml.NumberOperator(wires=i))
         for i in range(num_wires)
     ]
 def test_observable_with_no_eigvals(self):
     """An observable with no eigenvalues defined should cause
     the eigvals property on the associated measurement process
     to be None"""
     obs = qml.NumberOperator(wires=0)
     m = MeasurementProcess(Expectation, obs=obs)
     assert m.eigvals is None
Example #12
0
 def circuit(weights):
     qml.Squeezing(r, 0, wires=0)
     qml.Squeezing(r, 0, wires=1)
     qml.Squeezing(r, 0, wires=2)
     template(*weights, wires=[0, 1, 2])
     fn(template, *weights, wires=[0, 1, 2])
     return qml.expval(qml.NumberOperator(0))
    def test_multiple_squeezing_gradient(self, mocker, tol):
        """Test that the gradient of a circuit with two squeeze
        gates is correct."""
        dev = qml.device("default.gaussian", wires=2, hbar=hbar)

        r0, phi0, r1, phi1 = [0.4, -0.3, -0.7, 0.2]

        with qml.tape.JacobianTape() as tape:
            qml.Squeezing(r0, phi0, wires=[0])
            qml.Squeezing(r1, phi1, wires=[0])
            qml.expval(qml.NumberOperator(0))  # second order

        spy2 = mocker.spy(qml.gradients.parameter_shift_cv,
                          "second_order_param_shift")
        tapes, fn = param_shift_cv(tape, dev, force_order2=True)
        grad_A2 = fn(dev.batch_execute(tapes))
        spy2.assert_called()

        # check against the known analytic formula
        expected = np.zeros([4])
        expected[0] = np.cosh(2 * r1) * np.sinh(
            2 * r0) + np.cos(phi0 - phi1) * np.cosh(2 * r0) * np.sinh(2 * r1)
        expected[1] = -0.5 * np.sin(phi0 - phi1) * np.sinh(2 * r0) * np.sinh(
            2 * r1)
        expected[2] = np.cos(phi0 - phi1) * np.cosh(2 * r1) * np.sinh(
            2 * r0) + np.cosh(2 * r0) * np.sinh(2 * r1)
        expected[3] = 0.5 * np.sin(phi0 - phi1) * np.sinh(2 * r0) * np.sinh(
            2 * r1)

        assert np.allclose(grad_A2, expected, atol=tol, rtol=0)
Example #14
0
    def test_multiple_squeezing_gradient(self, mocker, tol):
        """Test that the gradient of a circuit with two squeeze
        gates is correct."""
        dev = qml.device("default.gaussian", wires=2, hbar=hbar)

        r0, phi0, r1, phi1 = [0.4, -0.3, -0.7, 0.2]

        with CVParamShiftTape() as tape:
            qml.Squeezing(r0, phi0, wires=[0])
            qml.Squeezing(r1, phi1, wires=[0])
            expval(qml.NumberOperator(0))  # second order

        tape._update_gradient_info()

        spy2 = mocker.spy(CVParamShiftTape, "parameter_shift_second_order")
        grad_A2 = tape.jacobian(dev, method="analytic", force_order2=True)
        spy2.assert_called()

        # check against the known analytic formula
        expected = np.zeros([4])
        expected[0] = np.cosh(2 * r1) * np.sinh(2 * r0) + np.cos(phi0 - phi1) * np.cosh(
            2 * r0
        ) * np.sinh(2 * r1)
        expected[1] = -0.5 * np.sin(phi0 - phi1) * np.sinh(2 * r0) * np.sinh(2 * r1)
        expected[2] = np.cos(phi0 - phi1) * np.cosh(2 * r1) * np.sinh(2 * r0) + np.cosh(
            2 * r0
        ) * np.sinh(2 * r1)
        expected[3] = 0.5 * np.sin(phi0 - phi1) * np.sinh(2 * r0) * np.sinh(2 * r1)

        assert np.allclose(grad_A2, expected, atol=tol, rtol=0)
Example #15
0
    def test_no_poly_xp_support(self, mocker, monkeypatch, caplog):
        """Test that if a device does not support PolyXP
        and the second-order parameter-shift rule is required,
        we fallback to finite differences."""
        dev = qml.device("default.gaussian", wires=1)

        monkeypatch.delitem(dev._observable_map, "PolyXP")

        with CVParamShiftTape() as tape:
            qml.Rotation(1.0, wires=[0])
            expval(qml.NumberOperator(0))

        tape.trainable_params = {0}
        assert tape.analytic_pd == tape.parameter_shift

        spy1 = mocker.spy(tape, "parameter_shift_first_order")
        spy2 = mocker.spy(tape, "parameter_shift_second_order")
        spy_transform = mocker.spy(qml.operation.CVOperation, "heisenberg_tr")
        spy_numeric = mocker.spy(tape, "numeric_pd")

        with pytest.warns(UserWarning, match="does not support the PolyXP observable"):
            tape.jacobian(dev, method="analytic")

        spy1.assert_not_called()
        spy2.assert_called()
        spy_transform.assert_not_called()
        spy_numeric.assert_called()
Example #16
0
 def circuit_tria(varphi):
     Interferometer(theta,
                    phi,
                    varphi,
                    mesh='triangular',
                    beamsplitter='clements',
                    wires=wires)
     return [qml.expval(qml.NumberOperator(w)) for w in wires]
Example #17
0
 def qf(x, y):
     qml.Displacement(x, 0,
                      wires=[0])  # followed by nongaussian observable
     qml.Beamsplitter(0.2, 1.7, wires=[0, 1])
     qml.Displacement(y, 0, wires=[1])  # followed by order-2 observable
     return qml.expval(qml.FockStateProjector(np.array([2]),
                                              0)), qml.expval(
                                                  qml.NumberOperator(1))
Example #18
0
            def circuit(*args):
                args = prep_par(args, op)
                op(*args, wires=wires)

                if issubclass(op, qml.operation.CV):
                    return qml.expval(qml.NumberOperator(0))
                else:
                    return qml.expval(qml.PauliZ(0))
 def circuit(varphi, bs=None):
     qml.templates.Interferometer(theta=[0.21],
                                  phi=[0.53],
                                  varphi=varphi,
                                  beamsplitter=bs,
                                  mesh=mesh,
                                  wires=[0, 1])
     return qml.expval(qml.NumberOperator(0))
        def circuit(theta, phi, varphi):
            for w in wires:
                qml.Squeezing(sq[w][0], sq[w][1], wires=w)

            qml.Interferometer(theta=theta,
                               phi=phi,
                               varphi=varphi,
                               wires=wires)
            return [qml.expval(qml.NumberOperator(w)) for w in wires]
    def test_second_order_expectation(self):
        """Test that the expectation of a second-order observable forces
        the gradient method to use the second-order parameter-shift rule"""

        with qml.tape.JacobianTape() as tape:
            qml.Rotation(1.0, wires=[0])
            qml.expval(qml.NumberOperator(0))  # second order

        assert _grad_method(tape, 0) == "A2"
Example #22
0
    def test_multiple_output_values(self, tol):
        """Tests correct output shape and evaluation for a tape
        with multiple outputs"""
        dev = qml.device("default.gaussian", wires=2)
        n = 0.543
        a = -0.654

        with JacobianTape() as tape:
            qml.ThermalState(n, wires=0)
            qml.Displacement(a, 0, wires=0)
            qml.expval(qml.NumberOperator(1))
            qml.var(qml.NumberOperator(0))

        tape.trainable_params = {0, 1}
        res = tape.jacobian(dev)
        assert res.shape == (2, 2)

        expected = np.array([[0, 0], [2 * a ** 2 + 2 * n + 1, 2 * a * (2 * n + 1)]])
        assert np.allclose(res, expected, atol=tol, rtol=0)
    def test_multiple_second_order_observables(self, mocker, tol):
        """Test that the gradient of a circuit with multiple
        second order observables is correct"""

        dev = qml.device("default.gaussian", wires=2, hbar=hbar)
        r = [0.4, -0.7, 0.1, 0.2]
        p = [0.1, 0.2, 0.3, 0.4]

        with qml.tape.JacobianTape() as tape:
            qml.Squeezing(r[0], p[0], wires=[0])
            qml.Squeezing(r[1], p[1], wires=[0])
            qml.Squeezing(r[2], p[2], wires=[1])
            qml.Squeezing(r[3], p[3], wires=[1])
            qml.expval(qml.NumberOperator(0))  # second order
            qml.expval(qml.NumberOperator(1))  # second order

        spy2 = mocker.spy(qml.gradients.parameter_shift_cv,
                          "second_order_param_shift")
        tapes, fn = param_shift_cv(tape, dev)
        grad_A2 = fn(dev.batch_execute(tapes))
        spy2.assert_called()

        # check against the known analytic formula

        def expected_grad(r, p):
            return np.array([
                np.cosh(2 * r[1]) * np.sinh(2 * r[0]) +
                np.cos(p[0] - p[1]) * np.cosh(2 * r[0]) * np.sinh(2 * r[1]),
                -0.5 * np.sin(p[0] - p[1]) * np.sinh(2 * r[0]) *
                np.sinh(2 * r[1]),
                np.cos(p[0] - p[1]) * np.cosh(2 * r[1]) * np.sinh(2 * r[0]) +
                np.cosh(2 * r[0]) * np.sinh(2 * r[1]),
                0.5 * np.sin(p[0] - p[1]) * np.sinh(2 * r[0]) *
                np.sinh(2 * r[1]),
            ])

        expected = np.zeros([2, 8])
        expected[0, :4] = expected_grad(r[:2], p[:2])
        expected[1, 4:] = expected_grad(r[2:], p[2:])

        assert np.allclose(grad_A2, expected, atol=tol, rtol=0)
    def test_multiple_second_order_observables(self, mocker, tol):
        """Test that the gradient of a circuit with multiple
        second order observables is correct"""

        dev = qml.device("default.gaussian", wires=2, hbar=hbar)
        r = [0.4, -0.7, 0.1, 0.2]
        p = [0.1, 0.2, 0.3, 0.4]

        with CVParamShiftTape() as tape:
            qml.Squeezing(r[0], p[0], wires=[0])
            qml.Squeezing(r[1], p[1], wires=[0])
            qml.Squeezing(r[2], p[2], wires=[1])
            qml.Squeezing(r[3], p[3], wires=[1])
            qml.expval(qml.NumberOperator(0))  # second order
            qml.expval(qml.NumberOperator(1))  # second order

        tape._update_gradient_info()

        spy2 = mocker.spy(CVParamShiftTape, "parameter_shift_second_order")
        grad_A2 = tape.jacobian(dev, method="analytic", force_order2=True)
        spy2.assert_called()

        # check against the known analytic formula

        def expected_grad(r, p):
            return np.array([
                np.cosh(2 * r[1]) * np.sinh(2 * r[0]) +
                np.cos(p[0] - p[1]) * np.cosh(2 * r[0]) * np.sinh(2 * r[1]),
                -0.5 * np.sin(p[0] - p[1]) * np.sinh(2 * r[0]) *
                np.sinh(2 * r[1]),
                np.cos(p[0] - p[1]) * np.cosh(2 * r[1]) * np.sinh(2 * r[0]) +
                np.cosh(2 * r[0]) * np.sinh(2 * r[1]),
                0.5 * np.sin(p[0] - p[1]) * np.sinh(2 * r[0]) *
                np.sinh(2 * r[1]),
            ])

        expected = np.zeros([2, 8])
        expected[0, :4] = expected_grad(r[:2], p[:2])
        expected[1, 4:] = expected_grad(r[2:], p[2:])

        assert np.allclose(grad_A2, expected, atol=tol, rtol=0)
Example #25
0
def quantum_neural_net(var, x):
    wires = list(range(len(x)))

    # Encode input x into a sequence of quantum fock states
    for i in wires:
        qml.FockState(x[i], wires=i)

    # "layer" subcircuits
    for i, v in enumerate(var):
        layer(v[:len(v) // 2], v[len(v) // 2:], wires)

    return [qml.expval(qml.NumberOperator(w)) for w in wires]
Example #26
0
    def test_error_analytic_second_order(self):
        """Test exception raised if attempting to use a second
        order observable to compute the variance derivative analytically"""
        dev = qml.device("default.gaussian", wires=1)

        with CVParamShiftTape() as tape:
            qml.Displacement(1.0, 0, wires=0)
            var(qml.NumberOperator(0))

        tape.trainable_params = {0}

        with pytest.raises(ValueError, match=r"cannot be used with the argument\(s\) \{0\}"):
            tape.jacobian(dev, method="analytic")
Example #27
0
def circuit(var):
    """Variational circuit.

    Args:
        var (array[float]): array containing the variables

    Returns:
        mean photon number of mode 0
    """
    qml.FockState(1, wires=0)
    qml.Beamsplitter(var[0], var[1], wires=[0, 1])

    return qml.expval(qml.NumberOperator(0))
    def test_second_order_transform(self, tol):
        """Test that a second order observable is transformed correctly"""
        # create a symmetric transformation
        Z = np.arange(3**2).reshape(3, 3)
        Z = Z.T + Z

        obs = qml.NumberOperator(0)
        res = _transform_observable(obs, Z, device_wires=[0])

        # The Heisenberg representation of the number operator
        # is (X^2 + P^2) / (2*hbar) - 1/2
        A = np.array([[-0.5, 0, 0], [0, 0.25, 0], [0, 0, 0.25]])
        expected = A @ Z + Z @ A

        assert isinstance(res, qml.PolyXP)
        assert res.wires.labels == (0, )
        assert np.allclose(res.data[0], expected, atol=tol, rtol=0)
Example #29
0
    def test_single_output_value(self, tol):
        """Tests correct execution and output shape for a CV tape
        with a single expval output"""
        dev = qml.device("default.gaussian", wires=2)
        x = 0.543
        y = -0.654

        with QuantumTape() as tape:
            qml.Displacement(x, 0, wires=[0])
            qml.Squeezing(y, 0, wires=[1])
            qml.Beamsplitter(np.pi / 4, 0, wires=[0, 1])
            qml.expval(qml.NumberOperator(0))

        assert tape.output_dim == 1

        res = tape.execute(dev)
        assert res.shape == (1, )
Example #30
0
    def test_single_output_value(self, tol):
        """Tests correct Jacobian and output shape for a CV tape
        with a single output"""
        dev = qml.device("default.gaussian", wires=2)
        n = 0.543
        a = -0.654

        with JacobianTape() as tape:
            qml.ThermalState(n, wires=0)
            qml.Displacement(a, 0, wires=0)
            qml.var(qml.NumberOperator(0))

        tape.trainable_params = {0, 1}
        res = tape.jacobian(dev)
        assert res.shape == (1, 2)

        expected = np.array([2 * a**2 + 2 * n + 1, 2 * a * (2 * n + 1)])
        assert np.allclose(res, expected, atol=tol, rtol=0)