Skip to content

Commit

Permalink
Add algorithmic errors tracking to qml.Tracker (#5465)
Browse files Browse the repository at this point in the history
**Context:** Update `qml.Tracker` to track and combine error

**Description of the Change:** Add algorithmic error tracking in the
`simulator_tracking` device modifier.

**Benefits:** `tracker` will track algorithmic errors. 

**Possible Drawbacks:** N/A

**Related GitHub Issues:** N/A

---------

Co-authored-by: Jay Soni <jbsoni@uwaterloo.ca>
  • Loading branch information
obliviateandsurrender and Jaybsoni committed Apr 12, 2024
1 parent d5e3b60 commit 9b60998
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 7 deletions.
4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
[stim](https://github.com/quantumlib/Stim) `v1.13.0`.
[(#5409)](https://github.com/PennyLaneAI/pennylane/pull/5409)

* `qml.specs` and `qml.Tracker` now return information about algorithmic errors for the qnode as well.
[(#5464)](https://github.com/PennyLaneAI/pennylane/pull/5464)
[(#5465)](https://github.com/PennyLaneAI/pennylane/pull/5465)

* `qml.specs` now returns information regarding algorithmic errors for the qnode as well.
[(#5464)](https://github.com/PennyLaneAI/pennylane/pull/5464)

Expand Down
12 changes: 8 additions & 4 deletions pennylane/devices/modifiers/simulator_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ def execute(self, circuits, execution_config=DefaultExecutionConfig):
results=r,
shots=shots,
resources=c.specs["resources"],
errors=c.specs["errors"],
)
else:
self.tracker.update(
simulations=1,
executions=qpu_executions,
results=r,
resources=c.specs["resources"],
errors=c.specs["errors"],
)
self.tracker.record()
return results
Expand Down Expand Up @@ -85,7 +87,7 @@ def execute_and_compute_derivatives(self, circuits, execution_config=DefaultExec
if self.tracker.active:
batch = (circuits,) if isinstance(circuits, QuantumScript) else circuits
for c in batch:
self.tracker.update(resources=c.specs["resources"])
self.tracker.update(resources=c.specs["resources"], errors=c.specs["errors"])
self.tracker.update(
execute_and_derivative_batches=1,
executions=len(batch),
Expand Down Expand Up @@ -119,7 +121,7 @@ def execute_and_compute_jvp(self, circuits, tangents, execution_config=DefaultEx
if self.tracker.active:
batch = (circuits,) if isinstance(circuits, QuantumScript) else circuits
for c in batch:
self.tracker.update(resources=c.specs["resources"])
self.tracker.update(resources=c.specs["resources"], errors=c.specs["errors"])
self.tracker.update(execute_and_jvp_batches=1, executions=len(batch), jvps=len(batch))
self.tracker.record()

Expand Down Expand Up @@ -153,7 +155,7 @@ def execute_and_compute_vjp(
if self.tracker.active:
batch = (circuits,) if isinstance(circuits, QuantumScript) else circuits
for c in batch:
self.tracker.update(resources=c.specs["resources"])
self.tracker.update(resources=c.specs["resources"], errors=c.specs["errors"])
self.tracker.update(execute_and_vjp_batches=1, executions=len(batch), vjps=len(batch))
self.tracker.record()
return untracked_execute_and_compute_vjp(self, circuits, cotangents, execution_config)
Expand All @@ -176,6 +178,7 @@ def simulator_tracking(cls: type) -> type:
* ``executions``: the number of unique circuits that would be required on quantum hardware
* ``shots``: the number of shots
* ``resources``: the :class:`~.resource.Resources` for the executed circuit.
* ``"errors"``: combined algorithmic errors from the quantum operations executed by the qnode.
* ``simulations``: the number of simulations performed. One simulation can cover multiple QPU executions,
such as for non-commuting measurements and batched parameters.
* ``batches``: The number of times :meth:`~pennylane.devices.Device.execute` is called.
Expand Down Expand Up @@ -218,7 +221,8 @@ def execute(self, circuits, execution_config = qml.devices.DefaultExecutionConfi
'shots': [100],
'resources': [Resources(num_wires=1, num_gates=1, gate_types=defaultdict(<class 'int'>, {'S': 1}),
gate_sizes=defaultdict(<class 'int'>, {1: 1}), depth=1, shots=Shots(total_shots=50,
shot_vector=(ShotCopies(50 shots x 1),)))]}
shot_vector=(ShotCopies(50 shots x 1),)))],
'errors': {}}
"""
if not issubclass(cls, Device):
Expand Down
4 changes: 3 additions & 1 deletion pennylane/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ def circuit(x):
gate_types=defaultdict(<class 'int'>, {'RX': 1}),
gate_sizes=defaultdict(<class 'int'>, {1: 1}),
depth=1,
shots=Shots(total_shots=100, shot_vector=(ShotCopies(100 shots x 1),)))}
shots=Shots(total_shots=100, shot_vector=(ShotCopies(100 shots x 1),))),
'errors': {}
}
>>> tracker.history.keys()
dict_keys(['batches', 'simulations', 'executions', 'results', 'shots', 'resources'])
>>> tracker.history['results']
Expand Down
3 changes: 3 additions & 0 deletions tests/devices/default_qubit/test_default_qubit_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def test_tracking_batch(self):
"resources": [Resources(num_wires=1), Resources(num_wires=1), Resources(num_wires=1)],
"derivative_batches": [1],
"derivatives": [1],
"errors": [{}, {}, {}],
}
assert tracker.totals == {
"batches": 2,
Expand All @@ -73,6 +74,7 @@ def test_tracking_batch(self):
"simulations": 1,
"results": 1,
"resources": Resources(num_wires=1),
"errors": {},
}

def test_tracking_execute_and_derivatives(self):
Expand Down Expand Up @@ -103,6 +105,7 @@ def test_tracking_execute_and_derivatives(self):
"vjp_batches": [1],
"execute_and_vjp_batches": [1],
"resources": [Resources(num_wires=1)] * 12,
"errors": [{}] * 12,
}

def test_tracking_resources(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/devices/modifiers/test_all_modifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def execute(self, circuits, execution_config=qml.devices.DefaultExecutionConfig)
# result unwrapped
assert out == 0.0

assert len(dev.tracker.history) == 6
assert len(dev.tracker.history) == 7
assert dev.tracker.history["batches"] == [1]
assert dev.tracker.history["simulations"] == [1]
assert dev.tracker.history["executions"] == [1]
Expand Down
2 changes: 1 addition & 1 deletion tests/devices/modifiers/test_simulator_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def execute(self, circuits, execution_config=qml.devices.DefaultExecutionConfig)
out = dev.execute((tape1, tape2))

assert out == ((0.0, 0.0), 0.0)
assert len(dev.tracker.history) == 6
assert len(dev.tracker.history) == 7
assert dev.tracker.history["batches"] == [1]
assert dev.tracker.history["simulations"] == [1, 1]
assert dev.tracker.history["executions"] == [2, 2]
Expand Down
1 change: 1 addition & 0 deletions tests/devices/test_default_clifford.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ def test_tracker():
"batches": [1, 1],
"simulations": [1, 1],
"executions": [1, 1],
"errors": [{}, {}],
}


Expand Down
1 change: 1 addition & 0 deletions tests/devices/test_null_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def test_tracking():
)
]
* 13,
"errors": [{}] * 13,
}


Expand Down
13 changes: 13 additions & 0 deletions tests/resource/test_error/test_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,16 @@ def test_specs(self):
assert algo_errors["MultiplicativeError"].error == 0.31 * 0.24
assert algo_errors["AdditiveError"].error == 0.73 + 0.12
assert algo_errors["SpectralNormError"].error == 0.25 + 0.17998560822421455

def test_tracker(self):
"""Test that tracker are tracking errors as expected."""

with qml.Tracker(self.dev) as tracker:
self.circuit()

algo_errors = tracker.latest["errors"]
assert len(algo_errors) == 3
assert all(error in algo_errors for error in self.errors_types)
assert algo_errors["MultiplicativeError"].error == 0.31 * 0.24
assert algo_errors["AdditiveError"].error == 0.73 + 0.12
assert algo_errors["SpectralNormError"].error == 0.25 + 0.17998560822421455

0 comments on commit 9b60998

Please sign in to comment.