Ejemplo n.º 1
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)
Ejemplo n.º 2
0
def test_batch_execute_parallel_tracker(mock_run_batch):
    """Asserts tracker updates during parallel execution"""

    mock_run_batch.return_value = TASK_BATCH
    type(TASK_BATCH).unsuccessful = PropertyMock(return_value={})
    dev = _aws_device(wires=1, foo="bar", parallel=True)

    with QuantumTape() as circuit:
        qml.Hadamard(wires=0)
        qml.probs(wires=(0, ))

    circuits = [circuit, circuit]

    callback = Mock()
    with qml.Tracker(dev, callback=callback) as tracker:
        dev.batch_execute(circuits)
    dev.batch_execute(circuits)

    latest = {"batches": 1, "executions": 2, "shots": 2 * SHOTS}
    history = {
        "batches": [1],
        "executions": [2],
        "shots": [2 * SHOTS],
        "braket_task_id": ["task_arn", "task_arn"],
    }
    totals = {"batches": 1, "executions": 2, "shots": 2 * SHOTS}
    assert tracker.latest == latest
    assert tracker.history == history
    assert tracker.totals == totals

    callback.assert_called_with(latest=latest, history=history, totals=totals)
    def test_fewer_device_invocations_vector_output(self):
        """Test that the hessian invokes less hardware executions than double differentiation
        (1d -> 1d)"""

        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, diff_method="parameter-shift", max_diff=2)
        def circuit(x):
            qml.RX(x[0], wires=0)
            qml.CNOT(wires=[0, 1])
            qml.RY(x[1], wires=0)
            qml.RZ(x[2], wires=1)
            return qml.probs(wires=[0, 1])

        x = np.array([0.1, 0.2, 0.3], requires_grad=True)

        with qml.Tracker(dev) as tracker:
            hessian = qml.gradients.param_shift_hessian(circuit)(x)
            hessian_qruns = tracker.totals["executions"]
            expected = qml.jacobian(qml.jacobian(circuit))(x)
            jacobian_qruns = tracker.totals["executions"] - hessian_qruns

        assert np.allclose(hessian, expected)
        assert hessian_qruns < jacobian_qruns
        assert hessian_qruns <= 2**2 * 6  # 6 = (3+2-1)C(2)
        assert hessian_qruns <= 3**3
Ejemplo n.º 4
0
def test_batch_execute_non_parallel_tracker(mock_run):
    """Tests tracking for a non-parallel batch"""
    mock_run.return_value = TASK
    dev = _aws_device(wires=2, foo="bar", parallel=False)

    with QuantumTape() as circuit:
        qml.Hadamard(wires=0)
        qml.probs(wires=(0, ))

    callback = Mock()
    with qml.Tracker(dev, callback=callback) as tracker:
        dev.batch_execute([circuit, circuit])
    dev.batch_execute([circuit])

    latest = {"batches": 1, "batch_len": 2}
    history = {
        "executions": [1, 1],
        "shots": [SHOTS, SHOTS],
        "batches": [1],
        "batch_len": [2],
        "braket_task_id": ["task_arn", "task_arn"],
    }
    totals = {
        "executions": 2,
        "shots": 2 * SHOTS,
        "batches": 1,
        "batch_len": 2
    }
    assert tracker.latest == latest
    assert tracker.history == history
    assert tracker.totals == totals

    callback.assert_called_with(latest=latest, history=history, totals=totals)
Ejemplo n.º 5
0
    def test_tracking(self, device, shots, tol):
        """Tests that a Device Tracker example correctly records resource usage"""

        # This test is run for both local and AWS managed simulators
        dev = device(1)

        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        x = np.array(0.1, requires_grad=True)

        with qml.Tracker(circuit.device) as tracker:
            qml.grad(circuit)(x)

        expected_totals = {
            "executions": 3,
            "shots": 300,
            "batches": 2,
            "batch_len": 3
        }
        expected_history = {
            "executions": [1, 1, 1],
            "shots": [100, 100, 100],
            "batches": [1, 1],
            "batch_len": [1, 2],
        }

        # Breaking change in PL 0.20 affects how many batches are created from the gradient
        if qml.version() < "0.20":
            expected_totals["batches"] = 1
            expected_totals["batch_len"] = 2
            expected_history["batches"] = [1]
            expected_history["batch_len"] = [2]

        expected_latest = {"batches": 1, "batch_len": 2}

        for key, total in expected_totals.items():
            assert tracker.totals[key] == total
        for key, history in expected_history.items():
            assert tracker.history[key] == history
        assert tracker.latest == expected_latest

        assert len(tracker.history["braket_task_id"]) == 3

        if type(dev) == BraketAwsQubitDevice:
            durations = tracker.history["braket_simulator_ms"]
            billed_durations = tracker.history["braket_simulator_billed_ms"]
            assert len(durations) == 3
            assert len(billed_durations) == 3
            for duration, billed in zip(durations, billed_durations):
                assert (duration < MIN_SIMULATOR_BILLED_MS and billed
                        == MIN_SIMULATOR_BILLED_MS) or duration == billed
Ejemplo n.º 6
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
                )
Ejemplo n.º 7
0
def test_batch_execute_partial_fail_parallel_tracker(mock_run_batch):
    """Asserts tracker updates during a partial failure of parallel execution"""

    FAIL_TASK = Mock()
    FAIL_TASK.result.return_value = None
    type(FAIL_TASK).id = PropertyMock(return_value="failed_task_arn")
    FAIL_TASK.state.return_value = "FAILED"
    FAIL_BATCH = Mock()
    FAIL_BATCH.results.side_effect = RuntimeError("tasks failed to complete")
    type(FAIL_BATCH).tasks = PropertyMock(return_value=[SIM_TASK, FAIL_TASK])
    type(FAIL_BATCH).unsuccessful = PropertyMock(
        return_value={"failed_task_arn"})

    mock_run_batch.return_value = FAIL_BATCH
    dev = _aws_device(wires=1, foo="bar", parallel=True)

    with QuantumTape() as circuit:
        qml.Hadamard(wires=0)
        qml.probs(wires=(0, ))

    circuits = [circuit, circuit]

    callback = Mock()
    try:
        with qml.Tracker(dev, callback=callback) as tracker:
            dev.batch_execute(circuits)
        dev.batch_execute(circuits)
    except RuntimeError:
        pass

    latest = {"batches": 1, "executions": 1, "shots": 1 * SHOTS}
    history = {
        "batches": [1],
        "executions": [1],
        "shots": [1 * SHOTS],
        "braket_task_id": ["task_arn"],
        "braket_failed_task_id": ["failed_task_arn"],
        "braket_simulator_ms": [1234],
        "braket_simulator_billed_ms": [3000],
    }
    totals = {
        "batches": 1,
        "executions": 1,
        "shots": 1 * SHOTS,
        "braket_simulator_ms": 1234,
        "braket_simulator_billed_ms": 3000,
    }
    assert tracker.latest == latest
    assert tracker.history == history
    assert tracker.totals == totals

    callback.assert_called_with(latest=latest, history=history, totals=totals)
Ejemplo n.º 8
0
    def test_tracker(self):
        """Tests the device tracker with batch execution."""
        dev = qml.device('qiskit.aer', shots=100, wires=3)

        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        x = tensor(0.1, requires_grad=True)

        with qml.Tracker(dev) as tracker:
            qml.grad(circuit)(x)

        expected = {'executions': [1, 1, 1],
                     'shots': [100, 100, 100],
                     'batches': [1, 1],
                     'batch_len': [1, 2]}

        assert tracker.history == expected
Ejemplo n.º 9
0
def test_execute_tracker(mock_run):
    """Asserts tracker stores information during execute when active"""
    mock_run.side_effect = [TASK, SIM_TASK, SIM_TASK, TASK]
    dev = _aws_device(wires=4, foo="bar")

    with QuantumTape() as circuit:
        qml.Hadamard(wires=0)
        qml.probs(wires=(0, ))

    callback = Mock()
    with qml.Tracker(dev, callback=callback) as tracker:
        dev.execute(circuit)
        dev.execute(circuit)
        dev.execute(circuit)
    dev.execute(circuit)

    latest = {
        "executions": 1,
        "shots": SHOTS,
        "braket_task_id": "task_arn",
        "braket_simulator_ms": 1234,
        "braket_simulator_billed_ms": 3000,
    }
    history = {
        "executions": [1, 1, 1],
        "shots": [SHOTS, SHOTS, SHOTS],
        "braket_task_id": ["task_arn", "task_arn", "task_arn"],
        "braket_simulator_ms": [1234, 1234],
        "braket_simulator_billed_ms": [3000, 3000],
    }
    totals = {
        "executions": 3,
        "shots": 3 * SHOTS,
        "braket_simulator_ms": 2468,
        "braket_simulator_billed_ms": 6000,
    }
    assert tracker.latest == latest
    assert tracker.history == history
    assert tracker.totals == totals

    callback.assert_called_with(latest=latest, history=history, totals=totals)
Ejemplo n.º 10
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)
Ejemplo n.º 11
0
    def __init__(self, wires=1, shots=1000, *, analytic=None):

        self.shots = shots

        if analytic is not None:
            msg = "The analytic argument has been replaced by shots=None. "
            msg += "Please use shots=None instead of analytic=True."
            raise DeviceError(msg)

        if not isinstance(wires, Iterable):
            # interpret wires as the number of consecutive wires
            wires = range(wires)

        self._wires = Wires(wires)
        self.num_wires = len(self._wires)
        self._wire_map = self.define_wire_map(self._wires)
        self._num_executions = 0
        self._op_queue = None
        self._obs_queue = None
        self._parameters = None

        self.tracker = qml.Tracker()
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
    def test_f0_argument(self):
        """Test that we can provide the results of a QNode to save on quantum invocations"""

        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, diff_method="parameter-shift", max_diff=2)
        def circuit(x):
            qml.RX(x[0], wires=0)
            qml.RY(x[1], wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.probs(wires=1)

        x = np.array([0.1, 0.2], requires_grad=True)

        res = circuit(x)

        with qml.Tracker(dev) as tracker:
            hessian1 = qml.gradients.param_shift_hessian(circuit, f0=res)(x)
            qruns1 = tracker.totals["executions"]
            hessian2 = qml.gradients.param_shift_hessian(circuit)(x)
            qruns2 = tracker.totals["executions"] - qruns1

        assert np.allclose(hessian1, hessian2)
        assert qruns1 < qruns2
Ejemplo n.º 14
0
    def test_fewer_device_invocations_scalar_input(self):
        """Test that the hessian invokes less hardware executions than double differentiation
        (0d -> 0d)"""

        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, diff_method="parameter-shift", max_diff=2)
        def circuit(x):
            qml.RX(x, wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(1))

        x = np.array(0.1, requires_grad=True)

        with qml.Tracker(dev) as tracker:
            hessian = qml.gradients.param_shift_hessian(circuit)(x)
            hessian_qruns = tracker.totals["executions"]
            expected = qml.jacobian(qml.jacobian(circuit))(x)
            jacobian_qruns = tracker.totals["executions"] - hessian_qruns

        assert np.allclose(hessian, expected)
        assert hessian_qruns < jacobian_qruns
        assert hessian_qruns <= 2**2 * 1  # 1 = (1+2-1)C(2)
        assert hessian_qruns <= 3**1
Ejemplo n.º 15
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)