The circuit inliner plugin¶

By default, circuits constructed by the pyAQASM library have a somewhat compressed structure.

Circuits consists in a main body, and each gate might have a subcircuit implementation that recursively describes the flow of the circuit.

Lets consider, for instance, a QFT adder:

In [1]:
# we define a simple function that prints the instructions in the main body of a circuit:
def print_main(circuit):
    from qat.core.util import extract_syntax
    for op in circuit.ops:
        print(extract_syntax(circuit.gateDic[op.gate], circuit.gateDic), op.qbits)
        
from qat.lang.AQASM import *
from qat.lang.AQASM.qftarith import add

prog = Program()
qbits = prog.qalloc(4)
prog.apply(add(2, 2), qbits)
circuit = prog.to_circ()

print_main(circuit)
('ADD', [2, 2]) [0, 1, 2, 3]

This is not very explicit. In fact, if one iterates over the circuit, we can see that the circuit contains many more instructions:

In [2]:
for op in circuit.iterate_simple():
    print(op)
('H', [], [1])
('C-PH', [1.5707963267948966], [0, 1])
('H', [], [0])
('C-PH', [3.141592653589793], [3, 1])
('C-PH', [1.5707963267948966], [2, 1])
('C-PH', [3.141592653589793], [2, 0])
('H', [], [0])
('C-PH', [-1.5707963267948966], [0, 1])
('H', [], [1])

What happened here is that the iterator iterate_simple emulated an execution stack when iterating over the circuit and unfolded the full circuit.

Equivalently, one could simply ask the to_circ method to unfold all the circuit:

In [3]:
circuit_full = prog.to_circ(inline=True)
print_main(circuit)
('ADD', [2, 2]) [0, 1, 2, 3]

CircuitInliner is a plugin that performs this inlining process in the stack. It should be used in case some other plugins requires an inlined circuit to run properly.

In [4]:
from qat.plugins import CircuitInliner
from qat.core import Batch
plugin = CircuitInliner()
print("==== Before 'compile'")
print_main(circuit)
batch = Batch(jobs=[circuit.to_job()])
batch = plugin.compile(batch, None)
print("==== After 'compile'")
print_main(circuit)
==== Before 'compile'
('ADD', [2, 2]) [0, 1, 2, 3]
==== After 'compile'
('H', []) [1]
('C-PH', [1.5707963267948966]) [0, 1]
('H', []) [0]
('C-PH', [3.141592653589793]) [3, 1]
('C-PH', [1.5707963267948966]) [2, 1]
('C-PH', [3.141592653589793]) [2, 0]
('H', []) [0]
('C-PH', [-1.5707963267948966]) [0, 1]
('H', []) [1]

As you can see, the circuit was modified in place. This behavior can be changed via the 'inplace' parameter:

In [5]:
circuit = prog.to_circ()
plugin = CircuitInliner(inplace=False)
print("==== Before 'compile'")
print_main(circuit)
batch = Batch(jobs=[circuit.to_job()])
batch = plugin.compile(batch, None)
print("==== After 'compile'")
print_main(circuit)
print("==== output:")
print_main(batch.jobs[0].circuit)
==== Before 'compile'
('ADD', [2, 2]) [0, 1, 2, 3]
==== After 'compile'
('ADD', [2, 2]) [0, 1, 2, 3]
==== output:
('H', []) [1]
('C-PH', [1.5707963267948966]) [0, 1]
('H', []) [0]
('C-PH', [3.141592653589793]) [3, 1]
('C-PH', [1.5707963267948966]) [2, 1]
('C-PH', [3.141592653589793]) [2, 0]
('H', []) [0]
('C-PH', [-1.5707963267948966]) [0, 1]
('H', []) [1]
In [ ]: