예제 #1
0
 def test_nums_frequency_and_spectra_missing(self):
     """Tests that an error is raised if neither information about the number
     of frequencies nor about the spectrum is given to ``reconstruct``."""
     with pytest.raises(
             ValueError,
             match="Either nums_frequency or spectra must be given."):
         reconstruct(dummy_qnode)
예제 #2
0
    def test_with_qnode(self, qnode, params, ids, nums_frequency, spectra,
                        shifts, exp_calls, mocker):
        """Run a full reconstruction on a QNode."""
        qnode = qml.QNode(qnode, dev_1)

        with qml.Tracker(qnode.device) as tracker:
            recons = reconstruct(qnode, ids, nums_frequency, spectra,
                                 shifts)(*params)
        assert tracker.totals["executions"] == exp_calls
        arg_names = list(signature(qnode.func).parameters.keys())
        for outer_key in recons:
            outer_key_num = arg_names.index(outer_key)
            for inner_key, rec in recons[outer_key].items():
                x0 = params[outer_key_num]
                if not pnp.isscalar(x0):
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec[inner_key] = 1.0
                shift_vec = 1.0 if pnp.isscalar(
                    params[outer_key_num]) else shift_vec
                mask = (0.0 if pnp.isscalar(params[outer_key_num]) else
                        pnp.ones(qml.math.shape(params[outer_key_num])) -
                        shift_vec)
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1:],
                )
                assert np.isclose(rec(x0), qnode(*params))
                assert np.isclose(rec(x0 + 0.1), univariate(x0 + 0.1))
                assert fun_close(rec, univariate, 10)
예제 #3
0
    def test_differentiability_torch(
        self, qnode, params, ids, nums_frequency, spectra, shifts, exp_calls, mocker
    ):
        """Tests the reconstruction and differentiability with Torch."""
        torch = pytest.importorskip("torch")
        qnode = qml.QNode(qnode, dev_1, interface="torch")
        params = tuple(torch.tensor(par, requires_grad=True, dtype=torch.float64) for par in params)
        if spectra is not None:
            spectra = {
                outer_key: {
                    inner_key: torch.tensor(val, dtype=torch.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in spectra.items()
            }
        if shifts is not None:
            shifts = {
                outer_key: {
                    inner_key: torch.tensor(val, dtype=torch.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in shifts.items()
            }
        with qml.Tracker(qnode.device) as tracker:
            recons = reconstruct(qnode, ids, nums_frequency, spectra, shifts)(*params)
        assert tracker.totals["executions"] == exp_calls
        arg_names = list(signature(qnode.func).parameters.keys())
        for outer_key in recons:
            outer_key_num = arg_names.index(outer_key)
            for inner_key, rec in recons[outer_key].items():
                x0 = params[outer_key_num]
                if not len(qml.math.shape(x0)) == 0:
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec = qml.math.scatter_element_add(shift_vec, inner_key, 1.0)
                    mask = torch.ones(qml.math.shape(params[outer_key_num])) - shift_vec
                else:
                    shift_vec = 1.0
                    mask = 0.0
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1 :],
                )
                exp_qnode_grad = torch.autograd.functional.jacobian(qnode, params)[outer_key_num]

                exp_grad = lambda x: torch.autograd.functional.jacobian(univariate, x)
                grad = lambda x: torch.autograd.functional.jacobian(rec, x)

                assert np.isclose(grad(x0), exp_qnode_grad[inner_key])
                assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
                assert fun_close(
                    grad, exp_grad, zero=torch.tensor(0.0, requires_grad=True), samples=10
                )
예제 #4
0
    def test_differentiability_jax(self, qnode, params, ids, nums_frequency,
                                   spectra, shifts, exp_calls, mocker):
        """Tests the reconstruction and differentiability with JAX."""
        jax = pytest.importorskip("jax")
        from jax.config import config

        config.update("jax_enable_x64", True)
        params = tuple(jax.numpy.array(par) for par in params)
        qnode = qml.QNode(qnode, dev_1, interface="jax")
        with qml.Tracker(qnode.device) as tracker:
            recons = reconstruct(qnode, ids, nums_frequency, spectra,
                                 shifts)(*params)
        assert tracker.totals["executions"] == exp_calls
        arg_names = list(signature(qnode.func).parameters.keys())
        for outer_key in recons:
            outer_key_num = arg_names.index(outer_key)
            for inner_key, rec in recons[outer_key].items():
                x0 = params[outer_key_num]
                if not pnp.isscalar(x0):
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec = qml.math.scatter_element_add(
                        shift_vec, inner_key, 1.0)
                shift_vec = 1.0 if pnp.isscalar(
                    params[outer_key_num]) else shift_vec
                mask = (0.0 if pnp.isscalar(params[outer_key_num]) else
                        pnp.ones(qml.math.shape(params[outer_key_num])) -
                        shift_vec)
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1:],
                )
                exp_qnode_grad = jax.grad(qnode, argnums=outer_key_num)
                exp_grad = jax.grad(univariate)
                grad = jax.grad(rec)
                assert np.isclose(grad(x0), exp_qnode_grad(*params)[inner_key])
                assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
                assert fun_close(grad, exp_grad, 10)
예제 #5
0
 def test_differentiability_autograd(self, qnode, params, ids,
                                     nums_frequency, spectra, shifts,
                                     exp_calls, mocker):
     """Tests the reconstruction and differentiability with autograd."""
     qnode = qml.QNode(qnode, dev_1, interface="autograd")
     with qml.Tracker(qnode.device) as tracker:
         recons = reconstruct(qnode, ids, nums_frequency, spectra,
                              shifts)(*params)
     assert tracker.totals["executions"] == exp_calls
     arg_names = list(signature(qnode.func).parameters.keys())
     for outer_key in recons:
         outer_key_num = arg_names.index(outer_key)
         for inner_key, rec in recons[outer_key].items():
             x0 = params[outer_key_num]
             if not pnp.isscalar(x0):
                 x0 = x0[inner_key]
                 shift_vec = qml.math.zeros_like(params[outer_key_num])
                 shift_vec[inner_key] = 1.0
             shift_vec = 1.0 if pnp.isscalar(
                 params[outer_key_num]) else shift_vec
             mask = (0.0 if pnp.isscalar(params[outer_key_num]) else
                     pnp.ones(qml.math.shape(params[outer_key_num])) -
                     shift_vec)
             univariate = lambda x: qnode(
                 *params[:outer_key_num],
                 params[outer_key_num] * mask + x * shift_vec,
                 *params[outer_key_num + 1:],
             )
             exp_qnode_grad = qml.grad(qnode, argnum=outer_key_num)
             exp_grad = qml.grad(univariate)
             grad = qml.grad(rec)
             if nums_frequency is None:
                 # Gradient evaluation at reconstruction point not supported for
                 # Dirichlet reconstruction
                 assert np.isclose(grad(x0),
                                   exp_qnode_grad(*params)[inner_key])
             assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
             assert fun_close(grad, exp_grad, 10)
예제 #6
0
 def test_wrong_number_of_shifts(self, spectra, shifts):
     """Tests that an error is raised if the number of provided shifts does not match."""
     with pytest.raises(ValueError, match="The number of provided shifts"):
         reconstruct(dummy_qnode, spectra=spectra, shifts=shifts)
예제 #7
0
    def test_differentiability_tensorflow(self, qnode, params, ids,
                                          nums_frequency, spectra, shifts,
                                          exp_calls, mocker):
        """Tests the reconstruction and differentiability with TensorFlow."""
        if qnode == qnode_4:
            pytest.skip(
                "Gradients are empty in TensorFlow for independent functions.")
        tf = pytest.importorskip("tensorflow")
        qnode = qml.QNode(qnode, dev_1, interface="tf")
        params = tuple(tf.Variable(par, dtype=tf.float64) for par in params)
        if spectra is not None:
            spectra = {
                outer_key: {
                    inner_key: tf.constant(val, dtype=tf.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in spectra.items()
            }
        if shifts is not None:
            shifts = {
                outer_key: {
                    inner_key: tf.constant(val, dtype=tf.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in shifts.items()
            }
        with qml.Tracker(qnode.device) as tracker:
            recons = reconstruct(qnode, ids, nums_frequency, spectra,
                                 shifts)(*params)
        assert tracker.totals["executions"] == exp_calls
        arg_names = list(signature(qnode.func).parameters.keys())
        for outer_key in recons:
            outer_key_num = arg_names.index(outer_key)
            for inner_key, rec in recons[outer_key].items():
                if outer_key == "Z" and inner_key == (1, 3):
                    # This is a constant function dependence, which can
                    # not be properly resolved by this test.
                    continue
                x0 = params[outer_key_num]
                if not len(qml.math.shape(x0)) == 0:
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec = qml.math.scatter_element_add(
                        shift_vec, inner_key, 1.0)
                    mask = pnp.ones(qml.math.shape(
                        params[outer_key_num])) - shift_vec
                else:
                    shift_vec = 1.0
                    mask = 0.0
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1:],
                )
                with tf.GradientTape() as tape:
                    out = qnode(*params)
                exp_qnode_grad = tape.gradient(out, params[outer_key_num])

                def exp_grad(x):
                    x = tf.Variable(x, dtype=tf.float64)
                    with tf.GradientTape() as tape:
                        out = univariate(x)
                    return tape.gradient(out, x)

                def grad(x):
                    x = tf.Variable(x, dtype=tf.float64)
                    with tf.GradientTape() as tape:
                        out = rec(x)
                    return tape.gradient(out, x)

                if nums_frequency is None:
                    # Gradient evaluation at reconstruction point not supported for
                    # Dirichlet reconstruction
                    assert np.isclose(grad(x0), exp_qnode_grad[inner_key])
                assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
                assert fun_close(grad, exp_grad, 10)