Circuit
Quantum circuits can be seen as DAGs (Direct Acyclic Graphs) in which the width of the DAG is constant and equal to the number of qubits. Also the indgree and outdegree of quantum gates must always be equal. But many state-of-art quantum circuit libraries use either (a) lists of moments of gates or (b) graphs for representing them, which do not exploit the sparsity of the circuit or already make decisions about their layout (thus not having a layout-independent representation).
Instead Quac uses multi-priority queues to store gates: there is a queue per qubit lane that stores the gates that act on it, and priorities are the order in which they are applied. If a gate acts on multiple qubits, it will contain a priority per qubit. This data structure allows us to store gates in the most compact way while iterating on gates, reversing the circuit, ... are still efficient. It appears to be the perfect data structure for quantum circuits.
No, the bottleneck of quantum circuits is not on their representation but when reading the source code of other quantum circuit libraries, I wasn't convinced by their solutions: graphs, already laid out lists of lists, a serialized list of gates, ... So I came up with multi-priority queues which seem like the perfect fit and as a consequence, the implementation is simple yet efficient.
Quac.Circuit — TypeA quantum circuit implementation using multi-priority queues.
- Queues are gate-buffers in qubit lanes.
- Multi-priority numbers can be retrieved procedurally from gate-lanes encoded inside the gates of the queues.
Methods
Base.adjointBase.hcatBase.isemptyBase.iterateBase.lengthBase.push!Base.vcatQuac.connectivityQuac.lanesQuac.moments
Base.adjoint — MethodBase.adjoint(circuit)Retrieve the adjoint circuit which fulfills the following equality.
circuit * circuit' == I(n)Notes
If all gates are hermitian, then the following equality also holds.
circuit * circuit' == circuit' * circuit == I(n)Base.hcat — Methodhcat(circuits::Circuit...)Join circuits in the temporal dimension.
Base.isempty — Methodisempty(circuit)Check whether the circuit contains any gate.
Base.iterate — MethodBase.iterate(circuit::Circuit[, state])Retrieves next gate from state by travelling through a topologically sorted path.
Arguments
circuit::Circuitstate(or head) should be aNTuple{N, Int}whereNis the number of lanes. Each element is a pointer to the next gate on each lane.
Base.length — Methodlength(circuit)Return the number of gates in a circuit.
Base.push! — Methodpush!(circuit, gate...)Appends a gate to the circuit.
Base.vcat — Methodvcat(circuits::Circuit...)Join circuits in the spatial dimension.
Quac.connectivity — Functionconnectivity([f,] circuit)Generate connectivity graph between qubits.
Arguments
- f: Function to filter gates from circuit.
- circuit: Circuit.
Quac.lanes — Methodlanes(circuit)Return the number of qubit lanes in a circuit.
Quac.moments — Functionmoments(circuit)Return moments (lists of gates that can execute at the same time) of the circuit.