Source code for QCut.backend_utility

"""
Utility functions for running on real backends.
"""

from __future__ import annotations

import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit_experiments.library import LocalReadoutError


[docs] def transpile_experiments(experiment_circuits: list, backend) -> list: """Transpile experiment circuits. Args: ----- experiment_circuits: experiment circuits backend: backend to transpile to Returns: -------- transpiled_experiments: a list of transpiled experiment circuits """ return [ [ transpile(circuit, backend, layout_method="sabre", optimization_level=3) for circuit in circuit_group ] for circuit_group in experiment_circuits ]
[docs] def run_and_expectation_value( circuit: QuantumCircuit, backend, observables: list, shots: int, mitigate=False ) -> tuple[dict, list]: """Run circuit and calculate expectation value. Args: ----- circuit: a quantum circuit backend: backend to run circuit on observables: observables to calculate expectation values for shots: number of shots mitigate: if True use readout error mitigation Returns: -------- expectation_values: a list of expectation values """ counts = run_on_backend(circuit, backend, shots) if mitigate: q = list(counts.keys()) qs = list(range(len(q[0]))) exp = LocalReadoutError(qs) exp.analysis.set_options(verbose=False) result = exp.run(backend) mitigator = result.analysis_results("Local Readout Mitigator").value mitigated_quasi_probs = mitigator.quasi_probabilities(counts) probs_test = { f"{int(old_key):0{len(qs)}b}"[::-1]: mitigated_quasi_probs[old_key] * shots if mitigated_quasi_probs[old_key] > 0 else 0 for old_key in mitigated_quasi_probs } counts = probs_test exps = expectation_values(counts, observables, shots) return counts, exps
[docs] def expectation_values(counts: dict, observables: list, shots: int) -> list: """Calculate expectation values. Args: ----- counts: counts obtained from circuit run observables: observables to calculate expectation values for shots: number of shots probs Returns: -------- cut_locations: a list of cut locations subcircuits: subcircuits with placeholder operations """ # Convert results to a list of dicts with measurement values and counts measurements = [ {"meas": [1 if bit == "0" else -1 for bit in meas], "count": count} for meas, count in counts.items() ] # Initialize an array to store expectation values for each observable exps = np.zeros(len(observables)) # Calculate expectation values for measurement in measurements: meas_values = measurement["meas"] count = measurement["count"] for idx, observable in enumerate(observables): if isinstance(observable, int): exps[idx] += meas_values[observable] * count else: exps[idx] += np.prod([meas_values[zi] for zi in observable]) * count return np.array(exps) / shots
[docs] def run_on_backend(circuit: QuantumCircuit, backend, shots: int) -> dict: """Run circuit on backend. Args: ----- circuit: a quantum circuit to be executed backend: backend to use for executing circuit shots: number of shots probs Returns: -------- dict: a dictionary of counts from circuit run """ job = backend.run(circuit, shots=shots) result = job.result() return result.get_counts()