Skip to content

Commit

Permalink
Fix bug causing slices with depth > 1 to be forward-prop'd (#62)
Browse files Browse the repository at this point in the history
* Fix bug, add test

* Update qiskit_addon_obp/backpropagation.py

Co-authored-by: Max Rossmannek <oss@zurich.ibm.com>

* peer review

* Update logger msg

* reno

* Cast to list for reversed

* Make op_nodes a list

---------

Co-authored-by: Max Rossmannek <oss@zurich.ibm.com>
  • Loading branch information
caleb-johnson and mrossinek authored Mar 5, 2025
1 parent 60b8ad3 commit ea445b3
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 21 deletions.
5 changes: 3 additions & 2 deletions qiskit_addon_obp/backpropagation.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ def handle_timeout(signum, frame):
# PERF: we will likely need to parallelize this loop
for i in range(num_observables):
non_trivial_slice = False
for op_idx, op_node in enumerate(circuit_to_dag(slice_).topological_op_nodes()):
op_nodes = list(circuit_to_dag(slice_).topological_op_nodes())[::-1]
for op_idx, op_node in enumerate(op_nodes):
# Ignore barriers within slices
if op_node.name == "barrier":
continue
Expand Down Expand Up @@ -214,7 +215,7 @@ def handle_timeout(signum, frame):
)

LOGGER.debug(
f"Size of the observable after backpropagating the {op_idx}-th gate in "
f"Size of the observable after backpropagating gate id {len(op_nodes) - op_idx - 1} in "
f"the current layer: {len(observables_tmp[i])}"
)

Expand Down
4 changes: 4 additions & 0 deletions releasenotes/notes/slice-bug-1aa7af1b87d4a9df.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
fixes:
- |
Fixed a bug in :func:`qiskit_addon_obp.backpropagate` which caused slices with depth > 1 to be incorrectly forward-propagated. Gates from a given slice will now be correctly propagated into the observable in reverse order (i.e., from the back of the slice).
34 changes: 15 additions & 19 deletions test/test_backpropagation.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ def test_backpropagate(self):
self.assertEqual({Pauli("IX"), Pauli("IY")}, set(new_obs[0].paulis))
self.assertEqual(0, len(slices))
self.assertEqual([], slices)

with self.subTest("Depth-2"):
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
obs = SparsePauliOp("ZZ")
target_obs = SparsePauliOp("ZI")
new_obs, slices, _ = backpropagate(obs, [qc])
self.assertEqual(target_obs, new_obs)
self.assertEqual([], slices)
with self.subTest("Scattered qargs"):
qc = QuantumCircuit(5)
obs = SparsePauliOp("XIYIZ")
Expand Down Expand Up @@ -512,47 +520,35 @@ def test_backpropagate(self):
new_obs, _, _ = backpropagate(
obs, [qc], truncation_error_budget=setup_budget(max_error_total=0.1, p_norm=2)
)
self.assertEqual(7, len(new_obs.paulis))
self.assertEqual(3, len(new_obs.paulis))
self.assertEqual(
{
Pauli("XX"),
Pauli("YX"),
Pauli("ZX"),
Pauli("XZ"),
Pauli("XY"),
Pauli("YY"),
Pauli("ZY"),
Pauli("IZ"),
},
set(new_obs.paulis),
)
# Budget to truncate smallest term
new_obs, _, _ = backpropagate(
obs, [qc], truncation_error_budget=setup_budget(max_error_total=0.2, p_norm=2)
obs, [qc], truncation_error_budget=setup_budget(max_error_total=0.26, p_norm=2)
)
self.assertEqual(6, len(new_obs.paulis))
self.assertEqual(2, len(new_obs.paulis))
self.assertEqual(
{
Pauli("XX"),
Pauli("ZX"),
Pauli("XY"),
Pauli("YY"),
Pauli("ZY"),
Pauli("IZ"),
},
set(new_obs.paulis),
)
# Budget to truncate 2 smallest terms
new_obs, _, _ = backpropagate(
obs, [qc], truncation_error_budget=setup_budget(max_error_total=0.29, p_norm=2)
obs, [qc], truncation_error_budget=setup_budget(max_error_total=0.501, p_norm=2)
)
self.assertEqual(5, len(new_obs.paulis))
self.assertEqual(1, len(new_obs.paulis))
self.assertEqual(
{
Pauli("XX"),
Pauli("XY"),
Pauli("YY"),
Pauli("ZY"),
Pauli("IZ"),
},
set(new_obs.paulis),
)
Expand Down

0 comments on commit ea445b3

Please sign in to comment.