Skip to content

Commit d92932c

Browse files
committed
Add support for saving/loading calibration parameters without schedules
5b6fa06 added support for saving and loading `Calibrations` objects with a JSON format that preserved calibrated gate schedules. However, it did not capture and restore the `Parameter` objects for calibration parameters (like `drive_freq`) which were not associated with a schedule. This commit adds support for these parameters by adding an entry to the serialization model that holds a placeholder `QuantumCircuit` with the parameters attached to placeholder instructions. `ExperimentEncoder` can serialize `QuantumCircuit` to qpy and so supports this format. Using a placeholder circuit like this is the only supported way to serialize `Parameter` objects. An alternative approach would be to store and retrieve the hidden attributes of the `Parameter` objects directly.
1 parent be220b2 commit d92932c

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

qiskit_experiments/calibration_management/save_utils.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
from datetime import datetime
4444
from typing import List, Dict, Any
4545

46+
from qiskit import QuantumCircuit
47+
from qiskit.circuit import Instruction
4648
from qiskit.pulse import ScheduleBlock
4749

4850
from .calibrations import Calibrations
@@ -118,6 +120,14 @@ class CalibrationModelV1:
118120
parameters: List[ParameterModelV1] = field(default_factory=list)
119121
"""List of calibrated pulse parameters."""
120122

123+
schedule_free_parameters: QuantumCircuit = field(default_factory=lambda: QuantumCircuit(1))
124+
"""Placeholder circuit for parameters not associated with a schedule
125+
126+
The circuit contains placeholder instructions which have the Parameter
127+
objects attached and operate on the qubits that the parameter is associated
128+
with in the calibrations.
129+
"""
130+
121131
schema_version: str = "1.0"
122132
"""Version of this data model. This must be static."""
123133

@@ -177,13 +187,26 @@ def calibrations_to_dict(
177187
sched_obj.metadata.update(qubit_metadata)
178188
sched_entries.append(sched_obj)
179189

190+
max_qubit = max(
191+
(max(k.qubits or (0,)) for k in cals._parameter_map if k.schedule is None),
192+
default=0,
193+
)
194+
schedule_free_parameters = QuantumCircuit(max_qubit + 1)
195+
for sched_key, param in cals._parameter_map.items():
196+
if sched_key.schedule is None:
197+
schedule_free_parameters.append(
198+
Instruction("parameter_container", len(sched_key.qubits), 0, [param]),
199+
sched_key.qubits,
200+
)
201+
180202
model = CalibrationModelV1(
181203
backend_name=cals.backend_name,
182204
backend_version=cals.backend_version,
183205
device_coupling_graph=getattr(cals, "_coupling_map"),
184206
control_channel_map=ControlChannelMap(getattr(cals, "_control_channel_map")),
185207
schedules=sched_entries,
186208
parameters=data_entries,
209+
schedule_free_parameters=schedule_free_parameters,
187210
)
188211

189212
return asdict(model)
@@ -257,6 +280,15 @@ def calibrations_from_dict(
257280
schedule=param.schedule,
258281
update_inst_map=False,
259282
)
283+
284+
for instruction in model.schedule_free_parameters.data:
285+
# For some reason, pylint thinks the items in data are tuples instead
286+
# of CircuitInstruction. Remove the following line if it ever stops
287+
# thinking that:
288+
# pylint: disable=no-member
289+
for param in instruction.operation.params:
290+
cals._register_parameter(param, instruction.qubits)
291+
260292
cals.update_inst_map()
261293

262294
return cals

test/calibration/test_calibrations.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
from test.base import QiskitExperimentsTestCase
1616
import os
17-
import unittest
1817
import uuid
1918
from collections import defaultdict
2019
from datetime import datetime, timezone, timedelta
@@ -1692,9 +1691,6 @@ def test_save_load_library_csv(self):
16921691
BackendData(backend).drive_freqs[0],
16931692
)
16941693

1695-
# Expected to fail because json calibration loading does not support
1696-
# restoring Parameter objects
1697-
@unittest.expectedFailure
16981694
def test_save_load_library(self):
16991695
"""Test that we can load and save a library.
17001696

0 commit comments

Comments
 (0)