Execution Metrics
Overview
When running a QESEM job, the results contain essential data to help you analyze the outcome of the QESEM execution. This data allows you to better understand the impact of different parameters on the QESEM execution. You might also find it relevan when writing a paper about your research. This guide explains each component of the job output and how to interpret them.
Noisy Results
The job.noisy_results
holds the expectation values and their respective error bar obtained by running the user's circuit without QESEM. It allows you to compare the performance of QESEM to bare execution at a given time. The following code snipped shows how to print the mitigated and noisy results side by side:
job = qedma_client.get_job(job_id = "<job_id>", include_results = True)
for observable, expectation_value in job.results:
noisy_value = [noisy_val for o, noisy_val in job.noisy_results if o==observable][0]
print(f"Observable: {observable}")
print(f"Mitigated value: {expectation_value}")
print(f"Noisy value: {noisy_value}")
Observable: {'X0,X1': 0.0058, 'X0,X1,X2,X3': 0.0124}
Mitigated value: -0.6426069139973665 ± 0.06942964571907104
Noisy value: -0.445530371314418 ± 0.03295058637115513
Number of Shots
These fields provide insight into total shots (includes calibration, characterization and mitigation) and only mitigation shots allocation, helping users understand:
- Characterization overhead – Can be much higher than necessary, especially for short mitigation jobs (≥1/2).
- Parameterized circuit efficiency – Shared characterization reduces the fraction of characterization shots.
- Scalability – Characterization becomes more efficient as qubits increase.
While users set the target precision, these fields help interpret the shot distribution and efficiency of QESEM.
job = qedma_client.get_job(job_id = "<job_id>")
print(f"Total shots: {job.execution_details.totle_shots}")
print(f"Mitigation shots: {job.execution_details.mitigation_shots}")
Total shots: 1259210
Mitigation shots: 253210
QPU Time
Another metric that QESEM exposes is the total billable QPU time which was required to execute the QESEM job. When execution mode is set to "session", job.qpu_time
is the session wall time. When execution mode is set to "batch", job.qpu_time
is the total qpu time used for all batches.
job = qedma_client.get_job(job_id = "<job_id>")
print(f"QPU time: {job.qpu_time['execution']}")
QPU time: 0:00:08
Note
The job.qpu_time
doesn't include the QPU time required for empirical time estimation
Gates Fidelities
job.execution_details.gate_fidelities
holds the average fidelity of each operation type in the transpiled circuit. Since these fidelities affect the time required for mitigation, they are valuable for understanding results and for making informed decisions. For example, comparing fidelities across devices can help identify the best device, and comparing fidelities across operation types can assist in circuit design.
Qedma’s characterization infers the Pauli error rates for all entangling layers in the circuit. The added infidelity due to single-qubit gates is accounted for within the two-qubit gate layer error budget. The infidelity of each operation within an entangling layer is computed by summing the Pauli error rates affecting its qubits, with crosstalk errors distributed evenly among the involved operations. The reported fidelities represent averages over all operations of a given type.
job = qedma_client.get_job(job_id = "<job_id>")
print(f"Gates fidelities: {job.execution_details.gate_fidelities}")
Gates fidelities: {'CNOT': 0.9900899581083492, 'ID1Q': 0.9989167673500885}
Transpiled Circuit
job.execution_details.transpiled_circuits
holds the quantum circuit after it has been adapted to the target hardware and optimized for qesem's mitigation QPU runtime. This involves converting the circuit to match device connectivity and native gates, utilizing both Clifford and fractional-angle entangling gates, and mapping logical qubits to physical qubits. The transpiled circuit serves as the basis for the mitigation: the circuits executed on the hardware maintain its structure, with only local modifications introduced during the mitigation process.
job = qedma_client.get_job(job_id = "<job_id>")
print(f"Transpiled circuit:")
print(job.execution_details.transpiled_circuits[0].circuit.draw(output="text", idle_wires=False, fold=10,vertical_compression='high'))
print(f"Transpiled circuit qubit mapping: {job.execution_details.transpiled_circuits[0].qubit_map}")
print(f"Transpiled circuit number of measurement bases: {job.execution_details.transpiled_circuits[0].num_measurement_bases}")
Transpiled circuit:
┌────────┐ ░ ┌────┐ ░ ┌──────────┐ ░ ┌────┐ ░ ┌────────┐ ░ ┌───┐ ░ ░ ┌────────────┐ ░ ┌────┐ ░ »
q1_31: ┤ Rz(-π) ├─░─┤ √X ├─░─┤ Rz(-π/2) ├─░─┤ √X ├─░─┤ Rz(-π) ├─░─┤ X ├─░──░─┤ Rz(1.4066) ├─░─┤ √X ├─░─»
├────────┤ ░ ├────┤ ░ ├──────────┤ ░ ├────┤ ░ ├────────┤ ░ └─┬─┘ ░ ░ └─┬────────┬─┘ ░ ├────┤ ░ »
q1_32: ┤ Rz(-π) ├─░─┤ √X ├─░─┤ Rz(-π/2) ├─░─┤ √X ├─░─┤ Rz(-π) ├─░───■───░──░───┤ Rz(-π) ├───░─┤ √X ├─░─»
└────────┘ ░ └────┘ ░ └──────────┘ ░ └────┘ ░ └────────┘ ░ ░ ░ └────────┘ ░ └────┘ ░ »
c0: 33/════════════════════════════════════════════════════════════════════════════════════════════════»
»
« ┌────────┐ ░ ┌────┐ ░ ┌─────────────┐ ░ ┌─────────┐┌───────┐┌────┐┌───────┐┌──────────┐ ░ ┌─┐
«q1_31: ─┤ Rz(-π) ├──░─┤ √X ├─░─┤ Rz(-1.4066) ├─░─┤ Rz(π/2) ├┤ Rz(π) ├┤ √X ├┤ Rz(π) ├┤ Rz(-π/2) ├─░─┤M├───
« ┌┴────────┴┐ ░ ├────┤ ░ └──┬────────┬─┘ ░ └─────────┘└───────┘└────┘└───────┘└──────────┘ ░ └╥┘┌─┐
«q1_32: ┤ Rz(-π/2) ├─░─┤ √X ├─░────┤ Rz(-π) ├───░─────────────────────────────────────────────────░──╫─┤M├
« └──────────┘ ░ └────┘ ░ └────────┘ ░ ░ ║ └╥┘
«c0: 33/═════════════════════════════════════════════════════════════════════════════════════════════╩══╩═
« Gates fidelities: {'CNOT': 0.989021363408563}
Transpiled circuit qubit mapping: {0: 32, 1: 31}
Transpiled circuit number of measurement bases: 1