Example: Zero Noise Extrapolation#

For folding methods, extrapolation options, and parameter details, see the ZNE guide.

Import everything needed#

from fiqci.ems import FiQCIEstimator
from iqm.qiskit_iqm import IQMProvider
from qiskit import QuantumCircuit, transpile
from qiskit.quantum_info import SparsePauliOp

Setup Estimator#

url = None
quantum_computer = None

# Connect to an IQM quantum computer using the provider
if url is not None and quantum_computer is not None:
	provider = IQMProvider(url=url, quantum_computer=quantum_computer)
	backend = provider.get_backend()
else:
	# Or using a noisy simulator
	from iqm.qiskit_iqm import IQMFakeAdonis

	backend = IQMFakeAdonis()

# Initialise FiQCI estimator with mitigation level 3 (readout error mitigation + zero-noise extrapolation)
estimator = FiQCIEstimator(backend=backend, mitigation_level=3)

# We can view the default settings enabled for mitigation level 3
estimator.mitigator_options
{'zne': {'enabled': True,
  'fold_gates': None,
  'scale_factors': [1, 3, 5],
  'folding_method': 'local',
  'extrapolation_method': 'exponential',
  'extrapolation_degree': None},
 'rem': {'enabled': True,
  'calibration_shots': 1000,
  'calibration_file': None,
  'mitigator': <fiqci.ems.mitigators.rem.M3IQM at 0x7fa47bb81b50>},
 'dd': {'enabled': True,
  'gate_sequences': [(9, 'XYXYYXYX', 'asap'),
   (5, 'YXYX', 'asap'),
   (2, 'XX', 'center')]},
 'pauli_twirl': {'enabled': False, 'num_twirls': 0, 'gates_to_twirl': None}}

Example circuit with ZNE + REM#

# Define a simple 5-qubit circuit
qc = QuantumCircuit(5)
qc.rx(0.5, 0)
qc.cx(0, 1)
qc.cx(0, 2)
qc.cx(0, 3)
qc.cx(0, 4)
qc.cx(1, 2)
qc.cx(1, 3)

# Transpile for backend
qc_transpiled = transpile(qc, backend=backend)

qc_transpiled.draw("mpl")
../_images/07bb0215e91d49491c35167a387b794cad61444d1f7bbb2d00947bcdd2570c17.png
# Define observables to calculate expectation values for (here Z on each qubit)
observables = SparsePauliOp.from_list([("ZIIII", 1), ("IZIII", 1), ("IIZII", 1), ("IIIZI", 1), ("IIIIZ", 1)])

# Map observables to the layout of the transpiled circuit
observables_device = observables.apply_layout(qc_transpiled.layout)

# Execute on FiQCI Estimator with specified observables and shots
job = estimator.run([qc_transpiled], observables=observables_device, shots=2**10)

# Retrieve mitigated expectation values
job.expectation_values()
[[0.8712768367247805,
  0.8712768367247805,
  0.8712768367247805,
  0.8712768367247805,
  0.8712768367247805]]

Manual Configuration#

# Initialise FiQCI estimator
estimator = FiQCIEstimator(backend=backend, mitigation_level=0)

# Configure ZNE
estimator.zne(enabled=True, scale_factors=[1, 5], extrapolation_method="richardson", folding_method="global")

# Print ZNE settings
estimator.mitigator_options
{'zne': {'enabled': True,
  'fold_gates': None,
  'scale_factors': [1, 5],
  'folding_method': 'local',
  'extrapolation_method': 'richardson',
  'extrapolation_degree': None},
 'rem': {'enabled': False,
  'calibration_shots': 1000,
  'calibration_file': None,
  'mitigator': None},
 'dd': {'enabled': False, 'gate_sequences': []},
 'pauli_twirl': {'enabled': False, 'num_twirls': 0, 'gates_to_twirl': None}}
# Execute the same circuit as above with only ZNE enabled (no readout error mitigation)
job = estimator.run([qc_transpiled], observables=observables_device, shots=2**10)
job.expectation_values()
[[0.75537109375, 0.75537109375, 0.75537109375, 0.75537109375, 0.75537109375]]