Skip to content

Revisit the circuit inversion logic and its implications for how we deal with Measure operations #12

Description

@mrossinek

Currently, the various bound computations going into the SLC, remove any Measure operations from the provided circuit. See:


There are 2 main reasons why we cannot handle Measure operations:

  1. they cannot be inverted (which speed_limit_bounds and compute_backward_bounds both do)
  2. they cannot be evolved through (which compute_forward_bounds tries to do)

The latter issue can be neglected for measure instructions that are final on the circuit, but QuantumCircuit.remove_final_measurements cannot correctly deal with final measurements that have been boxed op. Previously, we had attempted to remove these, but due to Qiskit/qiskit#14501 our approach also modified the original circuit, which is not good.

A proper implementation of removing final measurements even when inside a BoxOp at the end of a circuit is not immediately trivial and requires at least 1 traversal of the entire circuit. While such an approach has become simpler since the above mentioned Qiskit issue has been resolved, the approach is still not preferred as discussed further below.

Mid-circuit measurements are also not supported in the SLC bounds right now, but future research may enable them to be dealt with.


While in theory we can indeed write a function to remove only final measurements, the current approach of removing all Measure operations is more straight forward to implement and uses well established patterns from Qiskit SDK and, thus, is less likely to be a source of bugs.

Furthermore, I think a potentially more interesting direction for the future would be to avoid the QuantumCircuit.inverse calls entirely. This would also allow us to avoid monkeypatching BoxOp.inverse. Greedily replacing these circuit inversions with simple circuit-iteration-reversion seems to work just fine for our limited unittests, but this is surprising and should not be relied upon.

Let us investigate the current logic of the different steps:

Forward bounds

These bounds don't require any QuantumCircuit.inverse call. But since we iterate the circuit starting at its end and we unroll boxes as we encounter them, it is trivial to keep track of measure operations and whether they are final on their respective qubit or not, allowing us to differentiate terminal and mid-circuit measurements as we process them.

Speed-limit bounds

The current behavior is as follows:

  1. Let the input circuit be represented as: [g1, g2, ..., gN]
  2. We invert this circuit to become: [gN', ..., g2', g1']
  3. Now we iterate over this circuit in normal order, yielding:
    • gN'
    • ...
    • g2'
    • g1'
  4. At each iteration of the loop in 3, evolve the current LRL bounds (initialized with the observable we're after) under that gate. This evolution is done using a PTM.

If we replace the circuit inversion with order reversion, the workflow would become:

  1. Let the input circuit be represented as: [g1, g2, ..., gN]
  2. Iterate over this circuit in reverse, yielding:
    • gN
    • ...
    • g2
    • g1
  3. How would we need to update the evolution of the LRL bounds now? Is PTM(g) == PTM(g')? This would explain why doing this change does not affect the unittest outcome.

If we were able to make this implementation work, we could use the exact same tracking as in the forward bounds to determine whether an encountered Measure operation is final or not.

Backward bounds

Here, we also invert the circuit just like in the speed-limit case. But the current workflow re-uses the same bound computation logic as the forward bounds, meaning we iterate over the circuit in reverse:

  1. Let the input circuit be represented as: [g1, g2, ..., gN]
  2. We invert this circuit to become: [gN', ..., g2', g1']
  3. Now, we iterate over this circuit in reverse order, yielding:
    • g1'
    • g2'
    • ...
    • gN'
  4. At each iteration of the loop in 3, we move the Pauli error from that current layer through to the right end of this circuit (i.e. through all the layers previously iterated over).

If we want to avoid the QuantumCircuit.inverse call, replacing it with an iteration order in the reversed direction could look like the following:

  1. Let the input circuit be represented as: [g1, g2, ..., gN]
  2. Iterate over this circuit in normal order, yielding:
    • g1
    • g2
    • ...
    • gN
  3. Evolve the Pauli error to the left of the circiut (which is still all layers previously iterated over). Why does this also work without any additional changes with our current unittest? Would we not need to change Heisenberg<>Schroedinger frame evolution? Or does this cancel out by the fact that the gates we iterate over have not been inverted first?

In this case, we would not able to determine whether an encountered Measure operation is final or not very easily during the iteration. But the backward bounds only encounter these final measurements after gN, i.e. the very last iteration, for which the forward bounds are most likely a better bound anyways. So we could simply handle this case by falling back to a trivial bound value of 2.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions