qiskit-community / qiskit-experiments

Qiskit Experiments
https://qiskit-community.github.io/qiskit-experiments/
Apache License 2.0
160 stars 126 forks source link

Some BackendData properties raise exceptions when optional Target data is missing #1035

Closed wshanks closed 1 year ago

wshanks commented 1 year ago

Informations

What is the current behavior?

BackendData.coupling_map and BackendData.drive_freqs assume that Target.build_coupling_map() and Target.qubit_properties are iterable, but these attributes can also be None.

Steps to reproduce the problem

from qiskit_dynamics.backend import DynamicsBackend
from qiskit_experiments.calibration_management import Calibrations
from qiskit.transpiler import Target
from qiskit.circuit.library import XGate, SXGate

import numpy as np
from qiskit.quantum_info import Operator
from qiskit_dynamics import Solver

# construct operators
X = Operator.from_label('X')
Z = Operator.from_label('Z')

w = 5
r = 0.1
dt = 0.222
drift = 2 * np.pi * w * Z/2
operators = [2 * np.pi * r * X/2]

# construct the solver
solver = Solver(
    static_hamiltonian=drift,
    hamiltonian_operators=operators,
    rotating_frame=drift,
    rwa_cutoff_freq=2 * 5.0,
    hamiltonian_channels=['d0'],
    channel_carrier_freqs={'d0': w},
    dt=dt
)

backend = DynamicsBackend(solver)

backend.target.add_instruction(XGate())
backend.target.add_instruction(SXGate())

cals = Calibrations.from_backend(backend)

This code produces:

      4 backend.target.add_instruction(SXGate())
      5 
----> 6 cals = Calibrations.from_backend(backend)

/qiskit-experiments/qiskit_experiments/calibration_management/calibrations.py in from_backend(cls, backend, library, libraries, add_parameter_defaults)
    271 
    272         control_channel_map = {}
--> 273         for qargs in backend_data.coupling_map:
    274             control_channel_map[tuple(qargs)] = backend_data.control_channel(qargs)
    275 

/qiskit-experiments/qiskit_experiments/framework/backend_data.py in coupling_map(self)
    182             return getattr(self._backend.configuration(), "coupling_map", [])
    183         elif self._v2:
--> 184             return list(self._backend.coupling_map.get_edges())
    185         return []
    186 

AttributeError: 'NoneType' object has no attribute 'get_edges'

What is the expected behavior?

No error

Suggested solutions

Check that the underlying properties are not None before iterating on them in BackendData.

wshanks commented 1 year ago

One additional bug I want to lump in with these -- when there is no control channel data in the Target, BackendData.control_channel currently returns None, but the signature in BackendV2 is documented as returning a list, so returning an empty list would be more faithful to the underlying class.