Analyzing the output of a run¶
The aim of this notebook is to analyze in more detail the output of the submission of a job.
We will be focussing on the following simple circuit:
from qat.lang.AQASM import Program, H, CNOT, Y
prog = Program()
reg = prog.qalloc(2) # quantum register
creg = prog.calloc(3) # classical register
prog.apply(H, reg[0])
prog.apply(CNOT, reg)
prog.measure(reg[1], creg[1])
prog.cc_apply(creg[1], Y, reg[0])
prog.measure(reg[0], creg[0])
prog.logic(creg[2], ~ creg[1])
prog.reset(reg[1])
circ = prog.to_circ()
Let us examine the evolution of the quantum state step-by-step:
- we start in state $|00\rangle$ (bit order: q0 q1). The classical bits are in state "000" (bit order: b0 b1 b2).
- after the H and CNOT gates, we are in state $(|00\rangle + |11 \rangle)/\sqrt{2}$, the classical register is unchanged
- the first measure on qubit #1 projects the state to $|00\rangle$ or $|11\rangle$. The classical register is thus either in state "000" or "010"
- the classically controlled gate $Y$ is applied only if the second cbit has value 1, in which case we get the state $-i|01\rangle$. Otherwise, we keep the state $|00\rangle$.
- the second measure gives 0 in both possible cases ($-i|01\rangle$ and $|00\rangle$)
- the logic gate will give rise to the classical register state "010" or "001"
- the reset turns the classical register to "010" if the state was $-i|01\rangle$ (and yields final state $|-i|00\rangle$), or "001" if the state was $|00\rangle$ (and keeps the quantum state unchanged, $|00\rangle$.
In summary, we expect two possible intermediate measurement results:
- 0, 0, 0 (first two measures and reset), yielding final classical register "001" and quantum state $|00\rangle$
- 1, 0, 1 (first two measures and reset), yielding final classical register "010" and quantum state $-i|00\rangle$
We can now check that this is indeed what happens when executing this circuit on the QLM:
from qat.qpus import PyLinalg
qpu = PyLinalg()
# we execute the circuit 3 times
for _ in range(3):
res = qpu.submit(circ.to_job(nbshots=1, aggregate_data=False))
print("====================")
print(" ---- 3 intermediate measurements (including reset)---------------")
#print(res)
for meas_res in res.raw_data[0].intermediate_measurements:
print(" measure = %s (position = %s)"%(meas_res.cbits, meas_res.gate_pos))
print(" ---- final state of the quantum and classical register ------")
print(" quantum register = %s (bit order q0 q1)"% res.raw_data[0].state)
==================== ---- 3 intermediate measurements (including reset)--------------- measure = [np.int64(0)] (position = 2) measure = [np.int64(0)] (position = 4) measure = [np.int64(0)] (position = 6) ---- final state of the quantum and classical register ------ quantum register = |00> (bit order q0 q1) ==================== ---- 3 intermediate measurements (including reset)--------------- measure = [np.int64(0)] (position = 2) measure = [np.int64(0)] (position = 4) measure = [np.int64(0)] (position = 6) ---- final state of the quantum and classical register ------ quantum register = |00> (bit order q0 q1) ==================== ---- 3 intermediate measurements (including reset)--------------- measure = [np.int64(0)] (position = 2) measure = [np.int64(0)] (position = 4) measure = [np.int64(0)] (position = 6) ---- final state of the quantum and classical register ------ quantum register = |00> (bit order q0 q1)
We can see that res.raw_data is a list containing a objects (of the type Sample) containing several pieces of information:
its field
intermediate_measurementscontains a list of measurement results (typeMeasurementResult), which in particular contain the value of the measured bit(s) (fieldcbits) and the index of the measurement/reset gate in the circuit (fieldgate_pos)its field
statecontains the final quantum state after a measurement, in the computational basis, of all the qubits at the end of the circuit (one can also decide to measure only a subset of qubits at the end of the circuit, by specifying the parameterqubitsin the call toto_job)