boulder-opal-scale-up-sdk 1.0.0__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. boulder_opal_scale_up_sdk-1.0.2.dist-info/LICENSE +805 -0
  2. {boulder_opal_scale_up_sdk-1.0.0.dist-info → boulder_opal_scale_up_sdk-1.0.2.dist-info}/METADATA +17 -7
  3. boulder_opal_scale_up_sdk-1.0.2.dist-info/RECORD +60 -0
  4. boulderopalscaleupsdk/agent/worker.py +22 -11
  5. boulderopalscaleupsdk/common/dtypes.py +81 -114
  6. boulderopalscaleupsdk/device/__init__.py +5 -1
  7. boulderopalscaleupsdk/device/config_loader.py +15 -10
  8. boulderopalscaleupsdk/device/controller/__init__.py +17 -14
  9. boulderopalscaleupsdk/device/controller/base.py +12 -3
  10. boulderopalscaleupsdk/device/controller/qblox.py +43 -17
  11. boulderopalscaleupsdk/device/controller/quantum_machines.py +60 -59
  12. boulderopalscaleupsdk/device/controller/resolver.py +117 -0
  13. boulderopalscaleupsdk/device/defcal.py +62 -0
  14. boulderopalscaleupsdk/device/device.py +8 -2
  15. boulderopalscaleupsdk/device/processor/__init__.py +9 -1
  16. boulderopalscaleupsdk/device/processor/common.py +129 -20
  17. boulderopalscaleupsdk/device/processor/superconducting_processor.py +61 -15
  18. boulderopalscaleupsdk/experiments/__init__.py +8 -0
  19. boulderopalscaleupsdk/experiments/chi01_scan.py +56 -0
  20. boulderopalscaleupsdk/experiments/common.py +8 -4
  21. boulderopalscaleupsdk/experiments/power_rabi.py +3 -3
  22. boulderopalscaleupsdk/experiments/ramsey.py +15 -8
  23. boulderopalscaleupsdk/experiments/readout_classifier_calibration.py +24 -0
  24. boulderopalscaleupsdk/experiments/resonator_spectroscopy.py +3 -3
  25. boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_bias.py +10 -10
  26. boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_power.py +3 -3
  27. boulderopalscaleupsdk/experiments/transmon_anharmonicity.py +68 -0
  28. boulderopalscaleupsdk/experiments/transmon_spectroscopy.py +69 -0
  29. boulderopalscaleupsdk/grpc_interceptors/auth.py +5 -2
  30. boulderopalscaleupsdk/plotting/__init__.py +20 -2
  31. boulderopalscaleupsdk/plotting/dtypes.py +81 -117
  32. boulderopalscaleupsdk/protobuf/v1/agent_pb2.py +17 -17
  33. boulderopalscaleupsdk/protobuf/v1/agent_pb2.pyi +8 -6
  34. boulderopalscaleupsdk/protobuf/v1/agent_pb2_grpc.py +13 -13
  35. boulderopalscaleupsdk/protobuf/v1/device_pb2.py +43 -25
  36. boulderopalscaleupsdk/protobuf/v1/device_pb2.pyi +50 -8
  37. boulderopalscaleupsdk/protobuf/v1/device_pb2_grpc.py +116 -14
  38. boulderopalscaleupsdk/routines/__init__.py +1 -4
  39. boulderopalscaleupsdk/routines/resonator_mapping.py +8 -2
  40. boulderopalscaleupsdk/stubs/__init__.py +12 -0
  41. boulderopalscaleupsdk/stubs/dtypes.py +47 -0
  42. boulderopalscaleupsdk/stubs/maps.py +9 -0
  43. boulderopalscaleupsdk/third_party/quantum_machines/__init__.py +32 -0
  44. boulderopalscaleupsdk/third_party/quantum_machines/config.py +30 -9
  45. boulder_opal_scale_up_sdk-1.0.0.dist-info/RECORD +0 -50
  46. {boulder_opal_scale_up_sdk-1.0.0.dist-info → boulder_opal_scale_up_sdk-1.0.2.dist-info}/WHEEL +0 -0
@@ -12,12 +12,19 @@
12
12
  # License for the specific language.
13
13
 
14
14
  from collections.abc import Callable
15
- from datetime import datetime, timezone
16
- from typing import Annotated, Any, Generic, Literal, TypeVar
15
+ from datetime import UTC, datetime
16
+ from types import EllipsisType
17
+ from typing import Annotated, Any, Generic, Literal, Self, TypeVar
17
18
 
18
- from pydantic import BaseModel, BeforeValidator, ConfigDict, TypeAdapter
19
+ from pydantic import BeforeValidator, ConfigDict, TypeAdapter
20
+ from pydantic.dataclasses import dataclass
19
21
 
20
- from boulderopalscaleupsdk.common.dtypes import Duration, DurationNsLike, ISO8601DatetimeUTCLike
22
+ from boulderopalscaleupsdk.common.dtypes import (
23
+ Duration,
24
+ DurationNsLike,
25
+ Frequency,
26
+ ISO8601DatetimeUTCLike,
27
+ )
21
28
  from boulderopalscaleupsdk.common.typeclasses import Combine
22
29
 
23
30
  T = TypeVar("T")
@@ -25,8 +32,20 @@ T2 = TypeVar("T2")
25
32
  CalibrationStatusT = Literal["approximate", "bad", "good", "stale", "unmeasured"]
26
33
 
27
34
 
28
- class ComponentParameter(BaseModel, Generic[T]):
29
- dtype: Literal["component-parameter"] = "component-parameter"
35
+ @dataclass
36
+ class CalibrationThresholds:
37
+ good: float
38
+ approximate: float
39
+
40
+ def __post_init__(self):
41
+ if self.good <= 0 or self.approximate < self.good:
42
+ raise ValueError(
43
+ f"Invalid thresholds: good: {self.good}, approximate: {self.approximate}",
44
+ )
45
+
46
+
47
+ @dataclass
48
+ class ComponentParameter(Generic[T]):
30
49
  value: T
31
50
  err_minus: T | None = None
32
51
  err_plus: T | None = None
@@ -40,7 +59,7 @@ class ComponentParameter(BaseModel, Generic[T]):
40
59
  cls,
41
60
  value: Any,
42
61
  target_type: type[float | int | Duration],
43
- ) -> "ComponentParameter":
62
+ ) -> Self:
44
63
  """
45
64
  Create a ComponentParameter instance from a value, ensuring it matches the target type.
46
65
 
@@ -64,7 +83,7 @@ class ComponentParameter(BaseModel, Generic[T]):
64
83
  match value:
65
84
  case value if isinstance(value, cls):
66
85
  if not isinstance(value.value, target_type):
67
- raise TypeError("invalid value type")
86
+ raise TypeError("Invalid value type.")
68
87
  return value
69
88
  case _ if target_type in [float, int]:
70
89
  return cls(**value)
@@ -73,7 +92,7 @@ class ComponentParameter(BaseModel, Generic[T]):
73
92
  duration_ns = TypeAdapter(DurationNsLike).validate_python(value_copy.pop("value"))
74
93
  return cls(value=duration_ns, **value_copy) # type: ignore[arg-type]
75
94
  case _:
76
- return cls.model_validate(value)
95
+ raise TypeError("Invalid component value type.")
77
96
 
78
97
  @staticmethod
79
98
  def combine(
@@ -94,7 +113,7 @@ class ComponentParameter(BaseModel, Generic[T]):
94
113
  other.err_plus,
95
114
  ),
96
115
  calibration_status=other.calibration_status,
97
- updated_at=datetime.now(tz=timezone.utc),
116
+ updated_at=datetime.now(tz=UTC),
98
117
  )
99
118
 
100
119
  return Combine[ComponentParameter[T]].create(_combine)
@@ -116,23 +135,113 @@ class ComponentParameter(BaseModel, Generic[T]):
116
135
  self.calibration_status = combined.calibration_status
117
136
  self.updated_at = combined.updated_at
118
137
 
138
+ def update(
139
+ self,
140
+ *,
141
+ value: T | EllipsisType = ...,
142
+ err_minus: T | None | EllipsisType = ...,
143
+ err_plus: T | None | EllipsisType = ...,
144
+ calibration_status: CalibrationStatusT | EllipsisType = ...,
145
+ ) -> None:
146
+ if not isinstance(value, EllipsisType):
147
+ self.value = value
148
+ if not isinstance(err_minus, EllipsisType):
149
+ self.err_minus = err_minus
150
+ if not isinstance(err_plus, EllipsisType):
151
+ self.err_plus = err_plus
152
+ if not isinstance(calibration_status, EllipsisType):
153
+ self.calibration_status = calibration_status
154
+ self.updated_at = datetime.now(UTC)
155
+
156
+ def simple_update(
157
+ self,
158
+ *,
159
+ value: T | EllipsisType = ...,
160
+ std: T | None | EllipsisType = ...,
161
+ calibration_thresholds: CalibrationThresholds | EllipsisType = ...,
162
+ to_float: Callable[[T], float],
163
+ from_float: Callable[[float], T],
164
+ ) -> None:
165
+ if not isinstance(value, EllipsisType):
166
+ self.value = value
167
+ if not isinstance(std, EllipsisType):
168
+ if std is None:
169
+ self.err_minus = None
170
+ self.err_plus = None
171
+ else:
172
+ self.err_minus = from_float(to_float(std) / 2.0)
173
+ self.err_plus = from_float(to_float(std) / 2.0)
174
+ if (
175
+ not isinstance(calibration_thresholds, EllipsisType)
176
+ and self.err_minus is not None
177
+ and self.err_plus is not None
178
+ ):
179
+ self.calibration_status = _get_calibration_status_from_thresholds(
180
+ value=to_float(self.value),
181
+ confidence_interval=to_float(self.err_plus) - to_float(self.err_minus),
182
+ calibration_thresholds=calibration_thresholds,
183
+ )
184
+ self.updated_at = datetime.now(UTC)
185
+
186
+
187
+ def update_parameter(
188
+ parameter: ComponentParameter[T],
189
+ *,
190
+ value: T | EllipsisType = ...,
191
+ std: T | None | EllipsisType = ...,
192
+ calibration_thresholds: CalibrationThresholds | EllipsisType = ...,
193
+ ) -> None:
194
+ """
195
+ Update a ComponentParameter.
119
196
 
120
- def get_calibration_status_from_thresholds(
197
+ Parameters
198
+ ----------
199
+ parameter : ComponentParameter[T]
200
+ The parameter to update.
201
+ value : T | EllipsisType, optional
202
+ The parameter value. If not provided, the value is left unchanged.
203
+ std : T | None | EllipsisType, optional
204
+ The standard deviation to set the parameter errors.
205
+ If None, the errors are cleared.
206
+ If not provided, the error is left unchanged.
207
+ calibration_thresholds : CalibrationThresholds
208
+ The thresholds to update the calibration status.
209
+ If not provided, the status is left unchanged.
210
+ If the parameter errors are not set, the status is left unchanged.
211
+ """
212
+
213
+ # Use type of value to determine generic T.
214
+ match parameter.value:
215
+ case float():
216
+ parameter.simple_update(
217
+ value=value,
218
+ std=std,
219
+ calibration_thresholds=calibration_thresholds,
220
+ to_float=float, # type: ignore[arg-type]
221
+ from_float=float, # type: ignore[arg-type]
222
+ )
223
+ case Frequency():
224
+ parameter.simple_update(
225
+ value=value,
226
+ std=std,
227
+ calibration_thresholds=calibration_thresholds,
228
+ to_float=Frequency.to_float_hz, # type: ignore[arg-type]
229
+ from_float=Frequency.from_float_hz, # type: ignore[arg-type]
230
+ )
231
+ case _:
232
+ raise TypeError(f"Unsupported type in update: {type(parameter.value)}.")
233
+
234
+
235
+ def _get_calibration_status_from_thresholds(
121
236
  value: float,
122
237
  confidence_interval: float,
123
- good_threshold: float,
124
- approximate_threshold: float,
238
+ calibration_thresholds: CalibrationThresholds,
125
239
  ) -> CalibrationStatusT:
126
- if good_threshold <= 0 or approximate_threshold <= 0 or good_threshold >= approximate_threshold:
127
- raise ValueError(
128
- f"Invalid thresholds: good: {good_threshold}, approximate: {approximate_threshold}",
129
- )
130
-
131
240
  relative_uncertainty = abs(confidence_interval / value)
132
241
 
133
- if relative_uncertainty < good_threshold:
242
+ if relative_uncertainty < calibration_thresholds.good:
134
243
  return "good"
135
- if relative_uncertainty < approximate_threshold:
244
+ if relative_uncertainty < calibration_thresholds.approximate:
136
245
  return "approximate"
137
246
  return "bad"
138
247
 
@@ -14,7 +14,7 @@
14
14
  from copy import deepcopy
15
15
  from typing import Annotated, Any, Literal, Union, get_args, get_origin
16
16
 
17
- from pydantic import BaseModel, Field
17
+ from pydantic import BaseModel, Field, TypeAdapter
18
18
 
19
19
  from boulderopalscaleupsdk.common.dtypes import (
20
20
  Duration,
@@ -81,9 +81,9 @@ class Transmon(Component[Literal["tunable"]]):
81
81
  )
82
82
 
83
83
 
84
- class Resonator(Component[Literal["dispersive"]]):
84
+ class Resonator(Component[Literal["readout"]]):
85
85
  dtype: Literal["resonator"] = "resonator"
86
- traits: list[Literal["dispersive"]] = Field(default=["dispersive"])
86
+ traits: list[Literal["readout"]] = Field(default=["readout"])
87
87
 
88
88
  frequency_high: FloatComponentParameter | None = Field(
89
89
  default=None,
@@ -109,6 +109,33 @@ class Resonator(Component[Literal["dispersive"]]):
109
109
  default=ComponentParameter(value=0.0),
110
110
  json_schema_extra={"display": {"label": "vp_high", "unit": "V", "scale": 1}},
111
111
  )
112
+ purcell_coupling: FloatComponentParameter = Field(
113
+ default=ComponentParameter(value=0.0),
114
+ json_schema_extra={"display": {"label": "purcell_coupling", "unit": "MHz", "scale": 1e-6}},
115
+ )
116
+ purcell_frequency: FloatComponentParameter = Field(
117
+ default=ComponentParameter(value=0.0),
118
+ json_schema_extra={"display": {"label": "purcell_frequency", "unit": "MHz", "scale": 1e-6}},
119
+ )
120
+
121
+
122
+ class Coupler(Component[Literal["tunable"]]):
123
+ dtype: Literal["coupler"] = "coupler"
124
+ traits: list[Literal["tunable"]] = Field(default=["tunable"])
125
+
126
+ # Tunable coupler parameters
127
+ dc_bias: FloatComponentParameter = Field(
128
+ default=ComponentParameter(value=0.0),
129
+ json_schema_extra={"display": {"label": "dc_bias", "unit": "V", "scale": 1}},
130
+ )
131
+ fmax_bias: FloatComponentParameter = Field(
132
+ default=ComponentParameter(value=0.0),
133
+ json_schema_extra={"display": {"label": "fmax_bias", "unit": "V", "scale": 1}},
134
+ )
135
+ bias_period: FloatComponentParameter = Field(
136
+ default=ComponentParameter(value=0.0),
137
+ json_schema_extra={"display": {"label": "bias_period", "unit": "V", "scale": 1}},
138
+ )
112
139
 
113
140
 
114
141
  class Port(Component[Literal["drive", "readout", "flux"]]):
@@ -128,7 +155,7 @@ class Feedline(Component[Literal["feedline"]]):
128
155
  traits: list = Field(default=[])
129
156
 
130
157
 
131
- SuperconductingComponentType = Transmon | Resonator | Port | Feedline | Filter
158
+ SuperconductingComponentType = Transmon | Resonator | Port | Feedline | Filter | Coupler
132
159
 
133
160
 
134
161
  class Edge(BaseModel):
@@ -143,14 +170,14 @@ class TemplateParam(BaseModel):
143
170
 
144
171
 
145
172
  class ProcessorTemplate(BaseModel):
146
- elements: dict[str, Transmon | Resonator | Port | Feedline | Filter]
173
+ elements: dict[str, Transmon | Resonator | Port | Feedline | Filter | Coupler]
147
174
  edges: list[Edge]
148
175
 
149
176
 
150
177
  class SuperconductingProcessorTemplate(BaseModel):
151
178
  build: list[TemplateParam]
152
179
  templates: dict[str, ProcessorTemplate]
153
- device_parameters: dict[str, Transmon | Resonator | Port | Feedline | Filter] = Field(
180
+ device_parameters: dict[str, Transmon | Resonator | Port | Feedline | Filter | Coupler] = Field(
154
181
  default={},
155
182
  )
156
183
 
@@ -221,13 +248,32 @@ class SuperconductingProcessor(Processor):
221
248
  raise KeyError(f"Component with ID '{component_id}' does not exist.")
222
249
 
223
250
  component = self.nodes[component_id]
224
- replacement_component = {
225
- k: ComponentParameter(value=v).model_dump()
226
- if k not in ["dtype", "traits"] and v is not None
227
- else v
228
- for k, v in params.items()
229
- }
230
- self.nodes[component_id] = type(component).model_validate(replacement_component)
251
+ updated_component = deepcopy(component)
252
+
253
+ for k, v in params.items():
254
+ component_param = getattr(updated_component, k)
255
+ if not isinstance(component_param, ComponentParameter):
256
+ raise ValueError(f"Invalid or unexpected parameter for {type(component)}.") # noqa: TRY004
257
+
258
+ if k in ["dtype", "traits"]:
259
+ raise ValueError("Invalid attempt to modify component type or traits.")
260
+
261
+ if v is None:
262
+ continue
263
+
264
+ match v:
265
+ case ComponentParameter():
266
+ setattr(updated_component, k, v)
267
+ case _:
268
+ component_param.update(
269
+ value=v,
270
+ err_minus=None,
271
+ err_plus=None,
272
+ calibration_status="unmeasured",
273
+ )
274
+ setattr(updated_component, k, component_param)
275
+
276
+ self.nodes[component_id] = type(component).model_validate(updated_component.model_dump())
231
277
 
232
278
  def get_component(self, component_id: str) -> SuperconductingComponentType:
233
279
  """
@@ -279,13 +325,13 @@ def _coerce_component_params(
279
325
  continue
280
326
 
281
327
  try:
282
- dumped = value.model_dump()
328
+ dumped = TypeAdapter(type(value)).dump_python(value)
283
329
  coerced = expected_type(**dumped)
284
330
  setattr(component, field_name, coerced)
285
331
  except Exception as e:
286
332
  raise ValueError(
287
333
  f"Failed to coerce field '{field_name}' of type "
288
- "'{expected_type}' with value '{value}': {e}",
334
+ "'{expected_type}' with value '{value}': {e}.",
289
335
  ) from e
290
336
 
291
337
  return component
@@ -15,6 +15,7 @@
15
15
 
16
16
  __all__ = [
17
17
  "CWSIterable",
18
+ "Chi01Scan",
18
19
  "ConstantWaveform",
19
20
  "Experiment",
20
21
  "GaussianWaveform",
@@ -23,11 +24,15 @@ __all__ = [
23
24
  "PowerRabi",
24
25
  "Ramsey",
25
26
  "RangeIterable",
27
+ "ReadoutClassifierCalibration",
26
28
  "ResonatorSpectroscopy",
27
29
  "ResonatorSpectroscopyByBias",
28
30
  "ResonatorSpectroscopyByPower",
31
+ "TransmonAnharmonicity",
32
+ "TransmonSpectroscopy",
29
33
  ]
30
34
 
35
+ from .chi01_scan import Chi01Scan
31
36
  from .common import (
32
37
  ConstantWaveform,
33
38
  CWSIterable,
@@ -39,6 +44,9 @@ from .common import (
39
44
  )
40
45
  from .power_rabi import PowerRabi
41
46
  from .ramsey import Ramsey
47
+ from .readout_classifier_calibration import ReadoutClassifierCalibration
42
48
  from .resonator_spectroscopy import ResonatorSpectroscopy
43
49
  from .resonator_spectroscopy_by_bias import ResonatorSpectroscopyByBias
44
50
  from .resonator_spectroscopy_by_power import ResonatorSpectroscopyByPower
51
+ from .transmon_anharmonicity import TransmonAnharmonicity
52
+ from .transmon_spectroscopy import TransmonSpectroscopy
@@ -0,0 +1,56 @@
1
+ # Copyright 2025 Q-CTRL. All rights reserved.
2
+ #
3
+ # Licensed under the Q-CTRL Terms of service (the "License"). Unauthorized
4
+ # copying or use of this file, via any medium, is strictly prohibited.
5
+ # Proprietary and confidential. You may not use this file except in compliance
6
+ # with the License. You may obtain a copy of the License at
7
+ #
8
+ # https://q-ctrl.com/terms
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS. See the
12
+ # License for the specific language.
13
+
14
+ from pydantic import PrivateAttr
15
+
16
+ from boulderopalscaleupsdk.experiments.common import (
17
+ CWSIterable,
18
+ Experiment,
19
+ HypIterable,
20
+ LinspaceIterable,
21
+ RangeIterable,
22
+ )
23
+
24
+ DEFAULT_RECYCLE_DELAY_NS = 10_000
25
+ DEFAULT_SHOT_COUNT = 100
26
+
27
+
28
+ class Chi01Scan(Experiment):
29
+ """
30
+ Parameters for running an experiment to find the dispersive shift for a transmon
31
+ resonator pair.
32
+
33
+ Attributes
34
+ ----------
35
+ transmon : str
36
+ The reference for the transmon to target in the experiment.
37
+ frequencies : list[int] or LinspaceIterable or RangeIterable or CWSIterable
38
+ or HypIterable or None, optional
39
+ The frequencies at which to scan.
40
+ If None, frequencies around the readout frequency will be used.
41
+ recycle_delay_ns : int, optional
42
+ The delay time between consecutive shots of the experiment, in nanoseconds.
43
+ Defaults to 10000 ns.
44
+ shot_count : int, optional
45
+ The number of shots to be taken in the experiment.
46
+ Defaults to 100.
47
+ """
48
+
49
+ _experiment_name: str = PrivateAttr("chi01_scan")
50
+
51
+ transmon: str
52
+ frequencies: list[int] | LinspaceIterable | RangeIterable | CWSIterable | HypIterable | None = (
53
+ None
54
+ )
55
+ recycle_delay_ns: int = DEFAULT_RECYCLE_DELAY_NS
56
+ shot_count: int = DEFAULT_SHOT_COUNT
@@ -26,7 +26,11 @@ class Experiment(BaseModel):
26
26
  return self._experiment_name
27
27
 
28
28
 
29
- class LinspaceIterable(BaseModel):
29
+ class _RangeIterable(BaseModel):
30
+ model_config = ConfigDict(extra="forbid")
31
+
32
+
33
+ class LinspaceIterable(_RangeIterable):
30
34
  """A linear space of float values."""
31
35
 
32
36
  dtype: Literal["linspace"] = "linspace"
@@ -39,7 +43,7 @@ class LinspaceIterable(BaseModel):
39
43
  count: int = Field(default=101)
40
44
 
41
45
 
42
- class RangeIterable(BaseModel):
46
+ class RangeIterable(_RangeIterable):
43
47
  """A range of values with a specified step."""
44
48
 
45
49
  dtype: Literal["range"] = "range"
@@ -52,7 +56,7 @@ class RangeIterable(BaseModel):
52
56
  step: float
53
57
 
54
58
 
55
- class CWSIterable(BaseModel):
59
+ class CWSIterable(_RangeIterable):
56
60
  """A range of linearly spaced values in center ± width/2."""
57
61
 
58
62
  dtype: Literal["cws"] = "cws"
@@ -65,7 +69,7 @@ class CWSIterable(BaseModel):
65
69
  step: float
66
70
 
67
71
 
68
- class HypIterable(BaseModel):
72
+ class HypIterable(_RangeIterable):
69
73
  """
70
74
  A hyperbolic iterable of values in center ± width/2,
71
75
  with points more concentrated around the center.
@@ -32,8 +32,8 @@ class PowerRabi(Experiment):
32
32
 
33
33
  Parameters
34
34
  ----------
35
- qubit : int
36
- The qubit whose resonator to target in the experiment.
35
+ transmon : str
36
+ The reference for the transmon to target in the experiment.
37
37
  scales : list[float] or LinspaceIterable or RangeIterable
38
38
  or CWSIterable or HypIterable or None, optional
39
39
  The scaling factors for the drive pulse amplitude. If None, a default scan will be used.
@@ -51,7 +51,7 @@ class PowerRabi(Experiment):
51
51
 
52
52
  _experiment_name: str = PrivateAttr("power_rabi")
53
53
 
54
- qubit: int
54
+ transmon: str
55
55
  scales: list[float] | LinspaceIterable | RangeIterable | CWSIterable | HypIterable | None = None
56
56
  drive_waveform: GaussianWaveform
57
57
  measure_waveform: ConstantWaveform
@@ -17,6 +17,7 @@ from .common import Experiment
17
17
 
18
18
  DEFAULT_RECYCLE_DELAY_NS = 10_000
19
19
  DEFAULT_SHOT_COUNT = 400
20
+ DEFAULT_DURATION_NS = 2_000
20
21
 
21
22
 
22
23
  class Ramsey(Experiment):
@@ -25,18 +26,22 @@ class Ramsey(Experiment):
25
26
 
26
27
  Parameters
27
28
  ----------
28
- qubit : int
29
- The qubit whose resonator to target in the experiment.
29
+ transmon : str
30
+ The reference for the transmon to target in the experiment.
30
31
  max_delay_ns : int
31
32
  The maximum delay time, in nanoseconds.
32
33
  min_delay_ns : int
33
34
  The minimum delay time, in nanoseconds.
34
35
  delay_step_ns : int
35
36
  The step for generating the list of delays, in nanoseconds.
36
- detuning : float
37
- The difference between the drive signal frequency and the qubit frequency,
38
- in Hz.
39
- recycle_delay_ns : float, optional
37
+ virtual_detuning : float
38
+ The difference between the drive signal frequency and the qubit frequency, in Hz.
39
+ readout_amplitude : float
40
+ The amplitude of the readout pulse.
41
+ duration_ns : int, optional
42
+ The duration of the pulse, in nanoseconds.
43
+ Defaults to 2000 ns.
44
+ recycle_delay_ns : int, optional
40
45
  The delay time between consecutive shots of the experiment, in nanoseconds.
41
46
  Defaults to 10000 ns.
42
47
  shot_count : int, optional
@@ -46,10 +51,12 @@ class Ramsey(Experiment):
46
51
 
47
52
  _experiment_name: str = PrivateAttr("ramsey")
48
53
 
49
- qubit: int
54
+ transmon: str
50
55
  max_delay_ns: int
51
56
  min_delay_ns: int
52
57
  delay_step_ns: int
53
- detuning: float
58
+ virtual_detuning: float
59
+ readout_amplitude: float
60
+ duration_ns: int = DEFAULT_DURATION_NS
54
61
  recycle_delay_ns: int = DEFAULT_RECYCLE_DELAY_NS
55
62
  shot_count: int = DEFAULT_SHOT_COUNT
@@ -0,0 +1,24 @@
1
+ from pydantic import PrivateAttr
2
+
3
+ from boulderopalscaleupsdk.experiments.common import Experiment
4
+
5
+
6
+ class ReadoutClassifierCalibration(Experiment):
7
+ """
8
+ Parameters for running calibration of readout classifier for a transmon.
9
+
10
+ Parameters
11
+ ----------
12
+ transmon : str
13
+ The reference for the transmon to target in the experiment.
14
+ recycle_delay_ns : int
15
+ The delay time between consecutive shots of the experiment, in nanoseconds.
16
+ shot_count : int, optional
17
+ The number of shots to be taken in the experiment.
18
+ Defaults to 5000.
19
+ """
20
+
21
+ _experiment_name: str = PrivateAttr("readout_classifier_calibration")
22
+ transmon: str
23
+ recycle_delay_ns: int
24
+ shot_count: int = 5000
@@ -32,8 +32,8 @@ class ResonatorSpectroscopy(Experiment):
32
32
 
33
33
  Parameters
34
34
  ----------
35
- qubit : int
36
- The qubit whose resonator to target in the experiment.
35
+ resonator : str
36
+ The reference for the resonator to target in the experiment.
37
37
  frequencies : list[int] or LinspaceIterable or RangeIterable or CWSIterable
38
38
  or HypIterable or None, optional
39
39
  The frequencies at which to scan.
@@ -54,7 +54,7 @@ class ResonatorSpectroscopy(Experiment):
54
54
 
55
55
  _experiment_name: str = PrivateAttr("resonator_spectroscopy")
56
56
 
57
- qubit: int
57
+ resonator: str
58
58
  frequencies: list[int] | LinspaceIterable | RangeIterable | CWSIterable | HypIterable | None = (
59
59
  None
60
60
  )
@@ -33,12 +33,12 @@ class ResonatorSpectroscopyByBias(Experiment):
33
33
 
34
34
  Parameters
35
35
  ----------
36
- qubit : int
37
- The qubit whose resonator to target in the experiment.
38
- bias_qubits : list[int] or None, optional
39
- The qubits whose biases to target.
40
- If None, defaults to the qubit.
41
- frequencies : list[float] or LinspaceIterable or RangeIterable or CWSIterable
36
+ resonator : str
37
+ The reference for the resonator to target in the experiment.
38
+ bias_transmons : list[str] or None, optional
39
+ The transmons to bias.
40
+ If None, it defaults to transmon coupled to the resonator.
41
+ frequencies : list[int] or LinspaceIterable or RangeIterable or CWSIterable
42
42
  or HypIterable or None, optional
43
43
  The frequencies at which to scan.
44
44
  If None, frequencies around the readout frequency will be used.
@@ -49,10 +49,10 @@ class ResonatorSpectroscopyByBias(Experiment):
49
49
  readout_amplitude : float, optional
50
50
  The amplitude of the readout pulse.
51
51
  Defaults to None.
52
- duration_ns : float, optional
52
+ duration_ns : int, optional
53
53
  The duration of the pulse, in nanoseconds.
54
54
  Defaults to 2000 ns.
55
- recycle_delay_ns : float, optional
55
+ recycle_delay_ns : int, optional
56
56
  The delay time between consecutive shots of the experiment, in nanoseconds.
57
57
  Defaults to 10000 ns.
58
58
  shot_count : int, optional
@@ -62,8 +62,8 @@ class ResonatorSpectroscopyByBias(Experiment):
62
62
 
63
63
  _experiment_name: str = PrivateAttr("resonator_spectroscopy_by_bias")
64
64
 
65
- qubit: int
66
- bias_qubits: list[int] | None = None
65
+ resonator: str
66
+ bias_transmons: list[str] | None = None
67
67
  frequencies: list[int] | LinspaceIterable | RangeIterable | CWSIterable | HypIterable | None = (
68
68
  None
69
69
  )
@@ -32,8 +32,8 @@ class ResonatorSpectroscopyByPower(Experiment):
32
32
 
33
33
  Parameters
34
34
  ----------
35
- qubit : int
36
- The qubit whose resonator to target in the experiment.
35
+ resonator : str
36
+ The reference for the resonator to target in the experiment.
37
37
  frequencies : list[int] or LinspaceIterable or RangeIterable or CWSIterable
38
38
  or HypIterable or None, optional
39
39
  The frequencies at which to scan.
@@ -54,7 +54,7 @@ class ResonatorSpectroscopyByPower(Experiment):
54
54
 
55
55
  _experiment_name: str = PrivateAttr("resonator_spectroscopy_by_power")
56
56
 
57
- qubit: int
57
+ resonator: str
58
58
  frequencies: list[int] | LinspaceIterable | RangeIterable | CWSIterable | HypIterable | None = (
59
59
  None
60
60
  )