Circuit fusion#

The gates contained in a circuit can be fused up to two-qubits using the qibo.models.circuit.Circuit.fuse() method. This returns a new circuit for which the total number of gates is less than the gates in the original circuit as groups of gates have been fused to a single qibo.gates.special.FusedGate gate. Simulating the new circuit is equivalent to simulating the original one but in most cases more efficient since less gates need to be applied to the state vector.

The fusion algorithm works as follows: First all gates in the circuit are transformed to unmarked qibo.gates.special.FusedGate. The gates are then processed in the order they were added in the circuit. For each gate we identify the neighbors forth and back in time and attempt to fuse them to the gate. Two gates can be fused if their total number of target qubits is smaller than the fusion maximum qubits (specified by the user) and there are no other gates between acting on the same target qubits. Gates that are fused to others are marked. The new circuit queue contains the gates that remain unmarked after the above operations finish.

Gates are processed in the original order given by user. There are no additional simplifications performed such as commuting gates acting on the same qubit or canceling gates even when such simplifications are mathematically possible. The user can specify the maximum number of qubits in a fused gate using the max_qubits flag in qibo.models.circuit.Circuit.fuse().

For example the following:

from qibo import Circuit, gates

circuit = Circuit(2)
circuit.add([gates.H(0), gates.H(1)])
circuit.add(gates.CZ(0, 1))
circuit.add([gates.X(0), gates.Y(1)])
fused_circuit = circuit.fuse()

will create a new circuit with a single qibo.gates.special.FusedGate acting on (0, 1), while the following:

from qibo import Circuit, gates

circuit = Circuit(3)
circuit.add([gates.H(0), gates.H(1), gates.H(2)])
circuit.add(gates.CZ(0, 1))
circuit.add([gates.X(0), gates.Y(1), gates.Z(2)])
circuit.add(gates.CNOT(1, 2))
circuit.add([gates.H(0), gates.H(1), gates.H(2)])
fused_circuit = circuit.fuse()

will give a circuit with two fused gates, the first of which will act on (0, 1) corresponding to

[H(0), H(1), CZ(0, 1), X(0), H(0)]

and the second will act to (1, 2) corresponding to

[Y(1), Z(2), CNOT(1, 2), H(1), H(2)]