Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.1k stars 2.34k forks source link

Refactoring the Layout class #11604

Open sbrandhsn opened 8 months ago

sbrandhsn commented 8 months ago

What should we add?

When the Bit class becomes opaque (see #10996 ), the reference of Qubits in a quantum circuit must stay consistent during the execution of the python session. However, we can not guarantee this in all use cases. One example is the parallel execution of transpilation jobs where the user provides an initial layout. In these cases, the passmanager is serialized, leading to new Qubit instances and a thus mismatch of reference of the qubits between the quantum circuit to be transpiled and the Layout in the deserialized passmanager.

Thus, a refactoring of the Layout class is required with three proposal (so far):

  1. Remove all Bits from Layout and store the permutation only e.g. as a list or dictionary of integers. @levbishop
  2. Require the specification of a QuantumRegister whenever a Layout is initialized and store this information internally.
  3. Let Layout define the bijection $P \leftrightarrow V$ where $V$ is the set of BitLocations. BitLocations is a tuple $(i, R)$ with $i$ being the index of a bit within its quantum circuit and $R$ being a list of tuples $(r_i, r)$ with a register $r$ and bit index within a register $r_i$

I currently prefer proposal 3. as this gives you all information in one place.

jakelishman commented 8 months ago

We have to be careful about changing what's stored inside a Layout, because the Qubit instances representing the virtual bits are a fixed part of its public interface, and removing that will cause its current __getitem__ method (and several other methods) to break.

Bits have been able to have no index and register for quite some time already, so in theory, many of these problems likely already have some sort parts of solutions in the library - for example, we've largely moved away from using Layout as an input to transpiler passes (because of the serialisation problems), but it's still used when attached to a QuantumCircuit as a context object, where serialisation and deserialisation (and copy/deepcopy) have the bit instances to hand to do the remapping.

For point 3, I definitely agree it's got all the information in one place, but the trick to me is that the register information shouldn't be part of any comparison here. Comparing the names of registers (which are just ad-hoc named collections of bits) is something that really only QuantumCircuit would need to care about, if it decides (as it currently does) that circuits are equal if they have the same named structure to their bits. Duplicating that information in the Layout effectively ends up in us duplicating checks and restricting the Layout in ways that the user of Layout would already have to be validating in other ways anyway - it introduces additional sync between different structures, and I'm not clear that it actually applies a benefit for what a layout is meant to represent.

Point 1 is what (imo) we should do if we were starting the class from afresh; Layout represents a bi-directional mapping $V \leftrightarrow P$[^1], so all the information it needs to represent this is unique identifiers for virtual qubits and physical qubits. Whether we store the virtual qubit as an index or an tuple[index: int, locs: list[tuple[int, str]]] depends on how restrictive about accepting representations a Layout ought to be. Imo, it only makes sense to talk about virtual qubits in the context of a circuit, so then there's no advantage to having Layout carry the information about circuit structures as well.

[^1]: I have a problem with our current assumption of a bijection on both counts - I don't think we should be requiring either an injection or surjection! - but that's for another time.