Middle-end intermediate representation for fault-tolerant compilation - #82
Middle-end intermediate representation for fault-tolerant compilation#82Jake Lishman (jakelishman) wants to merge 2 commits into
Conversation
This is a design proposal for the new Qiskit middle-end intermediate representation (MIR). This draft of the document was informed by several workshops between IBM teams concerned with high-level and low-level parts of compilation, and tries to position useful abstractions to join up research efforts from algorithm design to compilation for exploratory hardware. This document defines the (initial) semantics, structure and behaviour of the new IR, and the motivation. It doesn't specify the implementation detail of _how_ this will be done; that is more of a technical design matter within the Qiskit SDK itself. The abstractions are all designed to be built on in order to form complete pipelines; the MIR definition alone deliberately does not restrict the semantics to any particular input language or backend ISA, but instead tries to provide a framework from which you can _define_ those things. Co-authored-by: Kit Barton <kbarton@ca.ibm.com>
| Jake roughly prefers the separated form, Kit roughly prefers the joined form, but neither of us have much beyond "it just feels familiar" in mind. | ||
| `QuantumCircuit` and `DAGCircuit`'s `Instruction`/`Gate` objects represent a complete "action" that is subsequently applied to "qubits", whereas it's unusual in most (non-quantum) compilers to separate out type of argument from another. | ||
| Certainly in the near term, the `qid` argument list represents quite different semantics to anything in the "symbol" list, but that might not always be the case. | ||
| [^memory-semantics]: This doesn't preclude us adding the concept of "arrays" or other references to memory in the future.( |
There was a problem hiding this comment.
| [^memory-semantics]: This doesn't preclude us adding the concept of "arrays" or other references to memory in the future.( | |
| [^memory-semantics]: This doesn't preclude us adding the concept of "arrays" or other references to memory in the future. |
| #### Qids | ||
|
|
||
| An "instruction" in Qiskit MIR takes zero or more `qid`s as arguments. | ||
| A `qid` has an optional "qubit width"; this defines how the built-in Pauli instructions act on it. |
There was a problem hiding this comment.
What is a situation in which you would not want to or be able to specify the qubit width of a qid?
There was a problem hiding this comment.
On the hardware side I was thinking about leaving space for e.g. modelling global operations on an interaction zone of an ion trap, that has say an indeterminate number of qubits, and potentially at the algorithm level, the ability to represent "some ancilla thing" at a high level having to commit to its qubit width til later in the pipeline.
Mostly, I don't think it costs us anything to leave it open, and had the benefit of constraining the future less; "no width" is just a just a special case of "widths don't match" when verifying instructions.
| [^qubit-semantics]: We don't have a full formal specification of "qubit semantics" yet, but it will follow. | ||
| For now, approximately think of them as "a resource that each instruction can use at most once and cannot copy". | ||
|
|
||
| #### Qids |
There was a problem hiding this comment.
Do qids have any notion of order of their underlying resources? Or is there any way for an instruction to specify the ordered content of a qid?
I am wondering if you would in general need distinct qids to, for example, describe the same 12 qubit module but in a different order. I don't think this comes up in bicycle architecture (iirc) because the instructions are hardcoded with respect to a particular ordering.
There was a problem hiding this comment.
Yes, I'd intended to make that possible as part of the bit-layout information tracking.
| [^instruction-parts]: We may want to add further metadata/annotations/whatever to individual instructions in the future. | ||
| We need to make sure the implementation and APIs don't make this unnecessarily hard. | ||
| [^separate-arg-lists]: It would also be a valid design to join the two argument lists and have `qid` be a type of symbol. | ||
| Jake roughly prefers the separated form, Kit roughly prefers the joined form, but neither of us have much beyond "it just feels familiar" in mind. |
There was a problem hiding this comment.
This IR uses value/data-flow semantics for classical information, but resource semantics for quantum information. You could imagine a fully value-semantic design, using linear typing for quantum state evolution as well, but this IR instead gives quantum resources stable identities and tracks them through the resource table. This, I imagine, is a very deliberate choice made by MIR because at this level of lowering we are interested in physical allocation of very scarce resources.
So I am also in favour of separation: the distinction between the two lists in the instruction components, I'd say, is that you first write down the resources you require to own, then you write down the operands accepted (ie list of existing values). If we introduced more kinds of exclusive resources, like locks or something, I'd put them in the first list.
There was a problem hiding this comment.
One argument in favour of joining them is that actually it's not that special to segregate by "semantics". While the types added in the initial draft all have value semantics, it's really pretty likely that at some point we'll have some concept of arrays / array-descriptors, and those imply some amount of shared memory access. Then you have to start thinking about that kind of alias analysis too, and it's not so clear that the segregation is making life much easier.
This, I imagine, is a very deliberate choice made by MIR because at this level of lowering we are interested in physical allocation of very scarce resources.
It is for sure, but don't forget that the qid system is also applied to the "virtual" / algorithmic upper end too, where you want to model (e.g.) some operations that treat a group of qubits as an "integer", but also permit operations on single bits within them, and have the data-flow analysis all work abstractly at compile time. At the virtual level, the resources aren't scarce (you're totally free to add more, provided you lower them later), but the compile-time alias analysis is all the same.
If we introduced more kinds of exclusive resources, like locks or something, I'd put them in the first list.
In some very vague way, this is related to me not wanting to require "things that behave like qids" to specify a qubit width, but I wasn't really thinking in terms of instruction-level locks. The framing of "you first write down the resources you require to own, then you write down the operands accepted" is, I think, roughly the same mental model I have that makes separation more palatable.
| A `qid` can "contain" other `qid`s. | ||
| If all relevant `qid`s have qubit-width information stored, the "contains" relationship includes which qubit indices in the "parent" the "child" refers to. | ||
| The complete set of "contains" relationships is an arbitrary DAG, where the nodes are `qid`s and the edges lead from container to contained. | ||
| Two `qid`s overlap if any other `qid` is reachable from both in the "contains" DAG. |
There was a problem hiding this comment.
I don't see how containment leads to overlaps if you don't in general promise a complete set of atomic units somewhere at the bottom. Up above, it reads like this isn't required.
Moreover seems like overlap is the property that will be more useful, in general. Should it be promoted to a required relation, rather than one derived from reachability under the assumption that all of the atomic qids have been introduced?
It could be that I'm just reading too much into what's written here. I get the underlying point of why you're setting things up with qids.
There was a problem hiding this comment.
The slightly hedgy wording here is to permit a structure like
0 1 2 3 4 5 6 7
|---8---|
|--9--| |--10-|
where 8 is neither contained by 9 or 10, but still overlaps them by leaf analysis that qid 3 is reachable by both 8 an 9, etc.
Moreover seems like overlap is the property that will be more useful, in general.
Yeah, the overlap is the important property/abstraction you get from the qid system - it defines the concept of the alias analysis.
Should it be promoted to a required relation, rather than one derived from reachability under the assumption that all of the atomic qids have been introduced?
I would reframe this: it is required, and it's not an assumption that all the atomic qids have been introduced, that's just the requirement that defines the concept of overlap. (This is another reason why qids aren't required to be fully associated with qubit widths - they can also just be "overlap" markers that define that two qids can't be used simultaneously. That could even be used to model something like "the control systems for these things are shared", in theory.)
There was a problem hiding this comment.
Okay I think I understand now. In the above example, you could get away with any two overlap markers with the right containments, and they need not be specific about [1,2,3] and [4,5].
This is a design proposal for the new Qiskit middle-end intermediate representation (MIR). This draft of the document was informed by several workshops between IBM teams concerned with high-level and low-level parts of compilation, and tries to position useful abstractions to join up research efforts from algorithm design to compilation for exploratory hardware.
This document defines the (initial) semantics, structure and behaviour of the new IR, and the motivation. It doesn't specify the implementation detail of how this will be done; that is more of a technical design matter within the Qiskit SDK itself.
The abstractions are all designed to be built on in order to form complete pipelines; the MIR definition alone deliberately does not restrict the semantics to any particular input language or backend ISA, but instead tries to provide a framework from which you can define those things.