Example: Expectation values with FiQCIEstimator#

For configuration options, mitigation levels, and result methods, see the FiQCIEstimator 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

Initialise FiQCIEstimator#

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 1 (readout error mitigation)
estimator = FiQCIEstimator(backend=backend, mitigation_level=1)

# We can view the default settings enabled for mitigation level 1
estimator.mitigator_options
{'zne': {'enabled': False,
  '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 0x7fa6f0650dd0>}}

Bell State expectation values with REM#

# Create a Bell state circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)

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

qc_transpiled.draw("mpl")
../_images/d9f5971906c9db290b89ace18aca3ea9f64f7e0edcb2e3b6ae3738d2c02ebbd7.png
# Define observables to calculate expectation values for
observables = SparsePauliOp.from_list([("ZZ", 1), ("IX", 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.9823874755381604, 0.004887585532746823]]

Access job metadata#

# Get all jobs
jobs = job.jobs()

# Get the first job
job0 = jobs[0]

# Access raw counts for the first job
raw_counts = job0.result().results[0].header["fiqci_ems"]["raw_counts"]

print(raw_counts)
{'01': 51, '11': 480, '10': 37, '00': 456}

Manually configure mitigation options#

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

# Config rem
estimator.rem(enabled=True, calibration_shots=2**10)

# Print current mitigator options
estimator.mitigator_options
{'zne': {'enabled': False,
  'fold_gates': None,
  'scale_factors': [1, 3, 5],
  'folding_method': 'local',
  'extrapolation_method': 'exponential',
  'extrapolation_degree': None},
 'rem': {'enabled': True,
  'calibration_shots': 1024,
  'calibration_file': None,
  'mitigator': <fiqci.ems.mitigators.rem.M3IQM at 0x7fa6f08a7230>}}

Access Job Information and Metadata#

# Estimator may execute multiple circuits depending on observables and mitigator settings. Here we fecth them all as a list
jobs = job.jobs()

# Look at the first job
job0 = jobs[0]

# Get the counts for the first job
print(job0.result().get_counts())

# Get raw counts for the circuit in the first job
print(job0.result().results[0].header)

raw_counts = job0.result().results[0].header["fiqci_ems"]["raw_counts"]

print(raw_counts)
[{'01': 9, '00': 491, '11': 522}, {'1': 509, '0': 514}]
{'creg_sizes': [['meas', 2]], 'global_phase': 0.0, 'memory_slots': 2, 'n_qubits': 5, 'name': 'circuit-13855', 'qreg_sizes': [['ancilla', 3], ['q', 2]], 'metadata': {}, 'fiqci_ems': {'mitigation_level': 1, 'mitigation_method': 'M3', 'calibration_shots': 1000, 'raw_counts': {'01': 51, '11': 480, '10': 37, '00': 456}}}
{'01': 51, '11': 480, '10': 37, '00': 456}