boulder-opal-scale-up-sdk 1.0.5__py3-none-any.whl → 1.0.7__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 (40) hide show
  1. {boulder_opal_scale_up_sdk-1.0.5.dist-info → boulder_opal_scale_up_sdk-1.0.7.dist-info}/METADATA +2 -2
  2. {boulder_opal_scale_up_sdk-1.0.5.dist-info → boulder_opal_scale_up_sdk-1.0.7.dist-info}/RECORD +38 -28
  3. boulderopalscaleupsdk/agent/worker.py +15 -2
  4. boulderopalscaleupsdk/common/dtypes.py +48 -4
  5. boulderopalscaleupsdk/{stubs/__init__.py → constants.py} +3 -0
  6. boulderopalscaleupsdk/device/controller/qblox.py +10 -2
  7. boulderopalscaleupsdk/device/controller/quantum_machines.py +86 -17
  8. boulderopalscaleupsdk/device/processor/common.py +3 -3
  9. boulderopalscaleupsdk/errors.py +21 -0
  10. boulderopalscaleupsdk/experiments/__init__.py +8 -2
  11. boulderopalscaleupsdk/experiments/cz_spectroscopy_by_bias.py +84 -0
  12. boulderopalscaleupsdk/experiments/power_rabi.py +1 -1
  13. boulderopalscaleupsdk/experiments/power_rabi_ef.py +1 -1
  14. boulderopalscaleupsdk/experiments/ramsey_ef.py +62 -0
  15. boulderopalscaleupsdk/experiments/{readout_classifier_calibration.py → readout_classifier.py} +7 -3
  16. boulderopalscaleupsdk/experiments/readout_optimization.py +57 -0
  17. boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_bias.py +2 -4
  18. boulderopalscaleupsdk/experiments/t2.py +1 -1
  19. boulderopalscaleupsdk/experiments/transmon_anharmonicity.py +0 -2
  20. boulderopalscaleupsdk/experiments/waveforms.py +15 -0
  21. boulderopalscaleupsdk/grpc_interceptors/error.py +318 -0
  22. boulderopalscaleupsdk/plotting/dtypes.py +5 -5
  23. boulderopalscaleupsdk/protobuf/v1/device_pb2.py +57 -49
  24. boulderopalscaleupsdk/protobuf/v1/device_pb2.pyi +76 -46
  25. boulderopalscaleupsdk/protobuf/v1/device_pb2_grpc.py +100 -66
  26. boulderopalscaleupsdk/protobuf/v1/job_pb2.py +47 -0
  27. boulderopalscaleupsdk/protobuf/v1/job_pb2.pyi +54 -0
  28. boulderopalscaleupsdk/protobuf/v1/job_pb2_grpc.py +138 -0
  29. boulderopalscaleupsdk/routines/__init__.py +2 -0
  30. boulderopalscaleupsdk/routines/coupler_discovery.py +37 -0
  31. boulderopalscaleupsdk/routines/transmon_retuning.py +0 -4
  32. boulderopalscaleupsdk/solutions/__init__.py +22 -0
  33. boulderopalscaleupsdk/solutions/common.py +23 -0
  34. boulderopalscaleupsdk/solutions/placeholder_solution.py +28 -0
  35. boulderopalscaleupsdk/third_party/quantum_machines/__init__.py +16 -1
  36. boulderopalscaleupsdk/third_party/quantum_machines/config.py +50 -50
  37. boulderopalscaleupsdk/stubs/dtypes.py +0 -47
  38. boulderopalscaleupsdk/stubs/maps.py +0 -18
  39. {boulder_opal_scale_up_sdk-1.0.5.dist-info → boulder_opal_scale_up_sdk-1.0.7.dist-info}/LICENSE +0 -0
  40. {boulder_opal_scale_up_sdk-1.0.5.dist-info → boulder_opal_scale_up_sdk-1.0.7.dist-info}/WHEEL +0 -0
@@ -0,0 +1,47 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: boulderopalscaleupsdk/protobuf/v1/job.proto
4
+ # Protobuf Python Version: 5.26.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2
16
+ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
17
+
18
+
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n+boulderopalscaleupsdk/protobuf/v1/job.proto\x12!boulderopalscaleupsdk.protobuf.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"*\n\x11GetSummaryRequest\x12\x15\n\x06job_id\x18\x01 \x01(\tR\x05jobId\"W\n\x12GetSummaryResponse\x12\x41\n\x10job_summary_data\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x0ejobSummaryData\"#\n\nGetRequest\x12\x15\n\x06job_id\x18\x01 \x01(\tR\x05jobId\"A\n\x0bGetResponse\x12\x32\n\x08job_data\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x07jobData\"\x92\x01\n\x0bListRequest\x12\x1f\n\x0b\x64\x65vice_name\x18\x01 \x01(\tR\ndeviceName\x12\x19\n\x08job_name\x18\x02 \x01(\tR\x07jobName\x12\x12\n\x04page\x18\x03 \x01(\x05R\x04page\x12\x14\n\x05limit\x18\x04 \x01(\x05R\x05limit\x12\x1d\n\nsort_order\x18\x05 \x01(\x05R\tsortOrder\"\\\n\x0cListResponse\x12+\n\x04jobs\x18\x01 \x03(\x0b\x32\x17.google.protobuf.StructR\x04jobs\x12\x1f\n\x0btotal_pages\x18\x02 \x01(\x05R\ntotalPages2\xb9\x03\n\x11JobManagerService\x12\x80\x01\n\x04List\x12..boulderopalscaleupsdk.protobuf.v1.ListRequest\x1a/.boulderopalscaleupsdk.protobuf.v1.ListResponse\"\x17\x82\xd3\xe4\x93\x02\x11\"\x0c/v1/job/list:\x01*\x12\x80\x01\n\x03Get\x12-.boulderopalscaleupsdk.protobuf.v1.GetRequest\x1a..boulderopalscaleupsdk.protobuf.v1.GetResponse\"\x1a\x82\xd3\xe4\x93\x02\x14\"\x0f/v1/job/get_job:\x01*\x12\x9d\x01\n\nGetSummary\x12\x34.boulderopalscaleupsdk.protobuf.v1.GetSummaryRequest\x1a\x35.boulderopalscaleupsdk.protobuf.v1.GetSummaryResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x17/v1/job/get_job_summary:\x01*B\xa7\x02\n%com.boulderopalscaleupsdk.protobuf.v1B\x08JobProtoP\x01ZNgithub.com/qctrl/boulder-opal-scale-up/proto/boulderopalscaleupsdk/protobuf/v1\xa2\x02\x03\x42PX\xaa\x02!Boulderopalscaleupsdk.Protobuf.V1\xca\x02!Boulderopalscaleupsdk\\Protobuf\\V1\xe2\x02-Boulderopalscaleupsdk\\Protobuf\\V1\\GPBMetadata\xea\x02#Boulderopalscaleupsdk::Protobuf::V1b\x06proto3')
20
+
21
+ _globals = globals()
22
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
23
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'boulderopalscaleupsdk.protobuf.v1.job_pb2', _globals)
24
+ if not _descriptor._USE_C_DESCRIPTORS:
25
+ _globals['DESCRIPTOR']._loaded_options = None
26
+ _globals['DESCRIPTOR']._serialized_options = b'\n%com.boulderopalscaleupsdk.protobuf.v1B\010JobProtoP\001ZNgithub.com/qctrl/boulder-opal-scale-up/proto/boulderopalscaleupsdk/protobuf/v1\242\002\003BPX\252\002!Boulderopalscaleupsdk.Protobuf.V1\312\002!Boulderopalscaleupsdk\\Protobuf\\V1\342\002-Boulderopalscaleupsdk\\Protobuf\\V1\\GPBMetadata\352\002#Boulderopalscaleupsdk::Protobuf::V1'
27
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['List']._loaded_options = None
28
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['List']._serialized_options = b'\202\323\344\223\002\021\"\014/v1/job/list:\001*'
29
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['Get']._loaded_options = None
30
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['Get']._serialized_options = b'\202\323\344\223\002\024\"\017/v1/job/get_job:\001*'
31
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['GetSummary']._loaded_options = None
32
+ _globals['_JOBMANAGERSERVICE'].methods_by_name['GetSummary']._serialized_options = b'\202\323\344\223\002\034\"\027/v1/job/get_job_summary:\001*'
33
+ _globals['_GETSUMMARYREQUEST']._serialized_start=142
34
+ _globals['_GETSUMMARYREQUEST']._serialized_end=184
35
+ _globals['_GETSUMMARYRESPONSE']._serialized_start=186
36
+ _globals['_GETSUMMARYRESPONSE']._serialized_end=273
37
+ _globals['_GETREQUEST']._serialized_start=275
38
+ _globals['_GETREQUEST']._serialized_end=310
39
+ _globals['_GETRESPONSE']._serialized_start=312
40
+ _globals['_GETRESPONSE']._serialized_end=377
41
+ _globals['_LISTREQUEST']._serialized_start=380
42
+ _globals['_LISTREQUEST']._serialized_end=526
43
+ _globals['_LISTRESPONSE']._serialized_start=528
44
+ _globals['_LISTRESPONSE']._serialized_end=620
45
+ _globals['_JOBMANAGERSERVICE']._serialized_start=623
46
+ _globals['_JOBMANAGERSERVICE']._serialized_end=1064
47
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,54 @@
1
+ from google.api import annotations_pb2 as _annotations_pb2
2
+ from google.protobuf import struct_pb2 as _struct_pb2
3
+ from google.protobuf.internal import containers as _containers
4
+ from google.protobuf import descriptor as _descriptor
5
+ from google.protobuf import message as _message
6
+ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
7
+
8
+ DESCRIPTOR: _descriptor.FileDescriptor
9
+
10
+ class GetSummaryRequest(_message.Message):
11
+ __slots__ = ("job_id",)
12
+ JOB_ID_FIELD_NUMBER: _ClassVar[int]
13
+ job_id: str
14
+ def __init__(self, job_id: _Optional[str] = ...) -> None: ...
15
+
16
+ class GetSummaryResponse(_message.Message):
17
+ __slots__ = ("job_summary_data",)
18
+ JOB_SUMMARY_DATA_FIELD_NUMBER: _ClassVar[int]
19
+ job_summary_data: _struct_pb2.Struct
20
+ def __init__(self, job_summary_data: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ...
21
+
22
+ class GetRequest(_message.Message):
23
+ __slots__ = ("job_id",)
24
+ JOB_ID_FIELD_NUMBER: _ClassVar[int]
25
+ job_id: str
26
+ def __init__(self, job_id: _Optional[str] = ...) -> None: ...
27
+
28
+ class GetResponse(_message.Message):
29
+ __slots__ = ("job_data",)
30
+ JOB_DATA_FIELD_NUMBER: _ClassVar[int]
31
+ job_data: _struct_pb2.Struct
32
+ def __init__(self, job_data: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ...
33
+
34
+ class ListRequest(_message.Message):
35
+ __slots__ = ("device_name", "job_name", "page", "limit", "sort_order")
36
+ DEVICE_NAME_FIELD_NUMBER: _ClassVar[int]
37
+ JOB_NAME_FIELD_NUMBER: _ClassVar[int]
38
+ PAGE_FIELD_NUMBER: _ClassVar[int]
39
+ LIMIT_FIELD_NUMBER: _ClassVar[int]
40
+ SORT_ORDER_FIELD_NUMBER: _ClassVar[int]
41
+ device_name: str
42
+ job_name: str
43
+ page: int
44
+ limit: int
45
+ sort_order: int
46
+ def __init__(self, device_name: _Optional[str] = ..., job_name: _Optional[str] = ..., page: _Optional[int] = ..., limit: _Optional[int] = ..., sort_order: _Optional[int] = ...) -> None: ...
47
+
48
+ class ListResponse(_message.Message):
49
+ __slots__ = ("jobs", "total_pages")
50
+ JOBS_FIELD_NUMBER: _ClassVar[int]
51
+ TOTAL_PAGES_FIELD_NUMBER: _ClassVar[int]
52
+ jobs: _containers.RepeatedCompositeFieldContainer[_struct_pb2.Struct]
53
+ total_pages: int
54
+ def __init__(self, jobs: _Optional[_Iterable[_Union[_struct_pb2.Struct, _Mapping]]] = ..., total_pages: _Optional[int] = ...) -> None: ...
@@ -0,0 +1,138 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
5
+ from boulderopalscaleupsdk.protobuf.v1 import job_pb2 as boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2
6
+
7
+
8
+ class JobManagerServiceStub(object):
9
+ """Job manager service.
10
+ """
11
+
12
+ def __init__(self, channel):
13
+ """Constructor.
14
+
15
+ Args:
16
+ channel: A grpc.Channel.
17
+ """
18
+ self.List = channel.unary_unary(
19
+ '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/List',
20
+ request_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListRequest.SerializeToString,
21
+ response_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListResponse.FromString,
22
+ )
23
+ self.Get = channel.unary_unary(
24
+ '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/Get',
25
+ request_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetRequest.SerializeToString,
26
+ response_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetResponse.FromString,
27
+ )
28
+ self.GetSummary = channel.unary_unary(
29
+ '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/GetSummary',
30
+ request_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryRequest.SerializeToString,
31
+ response_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryResponse.FromString,
32
+ )
33
+
34
+
35
+ class JobManagerServiceServicer(object):
36
+ """Job manager service.
37
+ """
38
+
39
+ def List(self, request, context):
40
+ """Fetch all the jobs that have been run on the device.
41
+ """
42
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
43
+ context.set_details('Method not implemented!')
44
+ raise NotImplementedError('Method not implemented!')
45
+
46
+ def Get(self, request, context):
47
+ """Fetch the results of a specific job executed on the device previously.
48
+ """
49
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
50
+ context.set_details('Method not implemented!')
51
+ raise NotImplementedError('Method not implemented!')
52
+
53
+ def GetSummary(self, request, context):
54
+ """Fetch the results view of a previously executed job.
55
+ """
56
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
57
+ context.set_details('Method not implemented!')
58
+ raise NotImplementedError('Method not implemented!')
59
+
60
+
61
+ def add_JobManagerServiceServicer_to_server(servicer, server):
62
+ rpc_method_handlers = {
63
+ 'List': grpc.unary_unary_rpc_method_handler(
64
+ servicer.List,
65
+ request_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListRequest.FromString,
66
+ response_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListResponse.SerializeToString,
67
+ ),
68
+ 'Get': grpc.unary_unary_rpc_method_handler(
69
+ servicer.Get,
70
+ request_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetRequest.FromString,
71
+ response_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetResponse.SerializeToString,
72
+ ),
73
+ 'GetSummary': grpc.unary_unary_rpc_method_handler(
74
+ servicer.GetSummary,
75
+ request_deserializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryRequest.FromString,
76
+ response_serializer=boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryResponse.SerializeToString,
77
+ ),
78
+ }
79
+ generic_handler = grpc.method_handlers_generic_handler(
80
+ 'boulderopalscaleupsdk.protobuf.v1.JobManagerService', rpc_method_handlers)
81
+ server.add_generic_rpc_handlers((generic_handler,))
82
+
83
+
84
+ # This class is part of an EXPERIMENTAL API.
85
+ class JobManagerService(object):
86
+ """Job manager service.
87
+ """
88
+
89
+ @staticmethod
90
+ def List(request,
91
+ target,
92
+ options=(),
93
+ channel_credentials=None,
94
+ call_credentials=None,
95
+ insecure=False,
96
+ compression=None,
97
+ wait_for_ready=None,
98
+ timeout=None,
99
+ metadata=None):
100
+ return grpc.experimental.unary_unary(request, target, '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/List',
101
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListRequest.SerializeToString,
102
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.ListResponse.FromString,
103
+ options, channel_credentials,
104
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
105
+
106
+ @staticmethod
107
+ def Get(request,
108
+ target,
109
+ options=(),
110
+ channel_credentials=None,
111
+ call_credentials=None,
112
+ insecure=False,
113
+ compression=None,
114
+ wait_for_ready=None,
115
+ timeout=None,
116
+ metadata=None):
117
+ return grpc.experimental.unary_unary(request, target, '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/Get',
118
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetRequest.SerializeToString,
119
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetResponse.FromString,
120
+ options, channel_credentials,
121
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
122
+
123
+ @staticmethod
124
+ def GetSummary(request,
125
+ target,
126
+ options=(),
127
+ channel_credentials=None,
128
+ call_credentials=None,
129
+ insecure=False,
130
+ compression=None,
131
+ wait_for_ready=None,
132
+ timeout=None,
133
+ metadata=None):
134
+ return grpc.experimental.unary_unary(request, target, '/boulderopalscaleupsdk.protobuf.v1.JobManagerService/GetSummary',
135
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryRequest.SerializeToString,
136
+ boulderopalscaleupsdk_dot_protobuf_dot_v1_dot_job__pb2.GetSummaryResponse.FromString,
137
+ options, channel_credentials,
138
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -14,6 +14,7 @@
14
14
  """Routine library."""
15
15
 
16
16
  __all__ = [
17
+ "CouplerDiscovery",
17
18
  "OneQubitCalibration",
18
19
  "ResonatorMapping",
19
20
  "Routine",
@@ -23,6 +24,7 @@ __all__ = [
23
24
  ]
24
25
 
25
26
  from .common import Routine
27
+ from .coupler_discovery import CouplerDiscovery
26
28
  from .one_qubit_calibration import OneQubitCalibration
27
29
  from .resonator_mapping import ResonatorMapping
28
30
  from .transmon_coherence import TransmonCoherence
@@ -0,0 +1,37 @@
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 .common import Routine
17
+
18
+
19
+ class CouplerDiscovery(Routine):
20
+ """
21
+ Parameters for running a coupler discovery routine.
22
+
23
+ Attributes
24
+ ----------
25
+ control_transmon : str
26
+ The reference for the transmon to use as control.
27
+ target_transmon : str
28
+ The reference for the transmon to target.
29
+ bias_values : list[float]
30
+ The list of bias values to sweep the coupler through.
31
+ """
32
+
33
+ _routine_name: str = PrivateAttr("coupler_discovery")
34
+
35
+ control_transmon: str
36
+ target_transmon: str
37
+ bias_values: list[float]
@@ -29,13 +29,9 @@ class TransmonRetuning(Routine):
29
29
  spectroscopy_waveform : ConstantWaveform or None, optional
30
30
  The drive pulse used during transmon spectroscopy.
31
31
  Defaults to a 10,000 ns pulse whose amplitude is defined by the logic of the experiment.
32
- force_rerun : bool, optional
33
- Whether to rerun the entire routine regardless transmon's current calibration status.
34
- Defaults to False.
35
32
  """
36
33
 
37
34
  _routine_name: str = PrivateAttr("transmon_retuning")
38
35
 
39
36
  transmon: str
40
37
  spectroscopy_waveform: ConstantWaveform | None = None
41
- force_rerun: bool = False
@@ -0,0 +1,22 @@
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
+ """Solution library."""
15
+
16
+ __all__ = [
17
+ "PlaceholderSolution",
18
+ "Solution",
19
+ ]
20
+
21
+ from .common import Solution
22
+ from .placeholder_solution import PlaceholderSolution
@@ -0,0 +1,23 @@
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 BaseModel, ConfigDict
15
+
16
+
17
+ class Solution(BaseModel):
18
+ model_config = ConfigDict(extra="forbid")
19
+ _solution_name: str
20
+
21
+ @property
22
+ def solution_name(self) -> str:
23
+ return self._solution_name
@@ -0,0 +1,28 @@
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
+ from typing_extensions import deprecated
16
+
17
+ from .common import Solution
18
+
19
+
20
+ @deprecated(
21
+ "This is a placeholder for a specific solution in the future.",
22
+ )
23
+ class PlaceholderSolution(Solution):
24
+ """
25
+ Parameters for running a placeholder solution.
26
+ """
27
+
28
+ _solution_name: str = PrivateAttr("placeholder_solution")
@@ -34,7 +34,7 @@ from unittest.mock import patch
34
34
 
35
35
  from packaging.version import Version
36
36
 
37
- if os.environ.get("QCTRL_SU_DISABLE_QM_LOGGING", "False") == "True":
37
+ if os.getenv("QCTRL_SU_DISABLE_QM_LOGGING", "False") == "True":
38
38
  # Disable QM logging and telemetry
39
39
  os.environ["QM_DISABLE_STREAMOUTPUT"] = "true" # Used in 1.1.0
40
40
  _qm_logger = logging.getLogger("qm")
@@ -51,6 +51,21 @@ _qm_patch_targets = [
51
51
  "qm.qua.AnalogMeasureProcess._get_loc",
52
52
  "qm.qua.DigitalMeasureProcess._get_loc",
53
53
  "qm.datadog_api.DatadogHandler",
54
+ "qm.qua.lib._get_loc",
55
+ "qm.qua._dsl.arbitrary._get_loc",
56
+ "qm.qua._dsl.calibration_params_update._get_loc",
57
+ "qm.qua._dsl.external_stream._get_loc",
58
+ "qm.qua._dsl.frame_rotation._get_loc",
59
+ "qm.qua._dsl.function_expressions._get_loc",
60
+ "qm.qua._dsl.phase_reset._get_loc",
61
+ "qm.qua._dsl.play._get_loc",
62
+ "qm.qua._dsl.pulses_utils._get_loc",
63
+ "qm.qua._dsl.scope_functions._get_loc",
64
+ "qm.qua._dsl.variable_handling._get_loc",
65
+ "qm.qua._dsl.wait._get_loc",
66
+ "qm.qua._dsl.measure.analog_measure_process._get_loc",
67
+ "qm.qua._dsl.measure.measure._get_loc",
68
+ "qm.qua._dsl.stream_processing.stream_processing._get_loc",
54
69
  ]
55
70
  for target in _qm_patch_targets:
56
71
  try:
@@ -84,13 +84,12 @@ For information about PyPA's version specifiers:
84
84
 
85
85
  # ruff: noqa: UP007, N815, E741
86
86
  from collections.abc import MutableMapping
87
- from typing import Annotated, Any, Literal, Self, TypeVar, Union
87
+ from typing import Annotated, Literal, NamedTuple, Self, TypeVar, Union
88
88
 
89
89
  from packaging.specifiers import SpecifierSet
90
90
  from packaging.version import Version
91
91
  from pydantic import (
92
92
  BaseModel,
93
- BeforeValidator,
94
93
  Discriminator,
95
94
  Field,
96
95
  PrivateAttr,
@@ -125,8 +124,18 @@ class Constants(BaseSettings):
125
124
  CONST = Constants()
126
125
 
127
126
 
128
- StandardPort = tuple[str, int, int]
129
- PortReferenceType = Union[tuple[str, int], StandardPort]
127
+ class NativeOPXPortType(NamedTuple):
128
+ controller_id: str
129
+ port_id: int
130
+
131
+
132
+ class NativeOPX1000PortType(NamedTuple):
133
+ controller_id: str
134
+ fem_id: int
135
+ port_id: int
136
+
137
+
138
+ QMPortTypes = NativeOPXPortType | NativeOPX1000PortType
130
139
 
131
140
 
132
141
  class AnalogOutputFilterConfigType(BaseModel):
@@ -134,24 +143,19 @@ class AnalogOutputFilterConfigType(BaseModel):
134
143
  feedback: list[float] = []
135
144
 
136
145
 
137
- def ensure_int(value: Any) -> Any:
138
- match value:
139
- case int():
140
- return value
141
- case str():
142
- return int(value)
143
- case _:
144
- raise ValueError("Field must be convertible to int.")
145
-
146
-
147
- IntLike = Annotated[int, BeforeValidator(ensure_int)]
146
+ class AnalogOutputFilterConfigType123(BaseModel):
147
+ feedforward: list[float] = []
148
+ feedback: list[float] = []
149
+ exponential: list[tuple[float, int]] = []
150
+ exponential_dc_gain: float | None = None
151
+ high_pass: float | None = None
148
152
 
149
153
 
150
154
  class AnalogOutputPortConfigType(BaseModel):
151
155
  offset: Number | None = None
152
156
  filter: AnalogOutputFilterConfigType | None = None
153
157
  delay: int | None = None
154
- crosstalk: Mapping[IntLike, Number] = {}
158
+ crosstalk: Mapping[int, Number] = {}
155
159
  shareable: bool | None = None
156
160
 
157
161
 
@@ -175,13 +179,12 @@ class DigitalInputPortConfigType(BaseModel):
175
179
  threshold: Number | None = None
176
180
 
177
181
 
178
- class AnalogOutputPortConfigTypeOctoDac(BaseModel):
182
+ class LfAnalogOutputPortConfigType(BaseModel):
179
183
  offset: Number | None = None
180
- filter: AnalogOutputFilterConfigType | None = None
184
+ filter: AnalogOutputFilterConfigType | AnalogOutputFilterConfigType123 | None = None
181
185
  delay: int | None = None
182
186
  crosstalk: Mapping[int, Number] = {}
183
187
  shareable: bool | None = None
184
- connectivity: tuple[str, str] | None = None
185
188
  sampling_rate: float | None = None
186
189
  upsampling_mode: Literal["mw", "pulse"] | None = None
187
190
  output_mode: Literal["direct", "amplified"] | None = None
@@ -189,10 +192,10 @@ class AnalogOutputPortConfigTypeOctoDac(BaseModel):
189
192
 
190
193
  class LfFemConfigType(BaseModel):
191
194
  type: Literal["LF"] | None = None
192
- analog_outputs: Mapping[int | str, AnalogOutputPortConfigTypeOctoDac] = {}
193
- analog_inputs: Mapping[int | str, AnalogInputPortConfigType] = {}
194
- digital_outputs: Mapping[int | str, DigitalOutputPortConfigType] = {}
195
- digital_inputs: Mapping[int | str, DigitalInputPortConfigType] = {}
195
+ analog_outputs: Mapping[int, LfAnalogOutputPortConfigType] = {}
196
+ analog_inputs: Mapping[int, AnalogInputPortConfigType] = {}
197
+ digital_outputs: Mapping[int, DigitalOutputPortConfigType] = {}
198
+ digital_inputs: Mapping[int, DigitalInputPortConfigType] = {}
196
199
 
197
200
 
198
201
  Band = Literal[1, 2, 3]
@@ -216,16 +219,16 @@ class MwFemAnalogOutputPortConfigType(BaseModel):
216
219
  band: Band | None = None
217
220
  delay: int | None = None
218
221
  shareable: bool | None = None
219
- upconverters: Mapping[IntLike, MwUpconverterConfigType] = {}
222
+ upconverters: Mapping[int, MwUpconverterConfigType] | None = None
220
223
  upconverter_frequency: float | None = None
221
224
 
222
225
 
223
226
  class MwFemConfigType(BaseModel):
224
227
  type: Literal["MW"] | None = None
225
- analog_outputs: Mapping[int | str, MwFemAnalogOutputPortConfigType] = {}
226
- analog_inputs: Mapping[int | str, MwFemAnalogInputPortConfigType] = {}
227
- digital_outputs: Mapping[int | str, DigitalOutputPortConfigType] = {}
228
- digital_inputs: Mapping[int | str, DigitalInputPortConfigType] = {}
228
+ analog_outputs: Mapping[int, MwFemAnalogOutputPortConfigType] = {}
229
+ analog_inputs: Mapping[int, MwFemAnalogInputPortConfigType] = {}
230
+ digital_outputs: Mapping[int, DigitalOutputPortConfigType] = {}
231
+ digital_inputs: Mapping[int, DigitalInputPortConfigType] = {}
229
232
 
230
233
 
231
234
  class ControllerConfigType(BaseModel):
@@ -247,8 +250,8 @@ class OctaveRFOutputConfigType(BaseModel):
247
250
  ] = "always_off"
248
251
  gain: int | float = Field(default=0, ge=-20, le=20, multiple_of=0.5)
249
252
  input_attenuators: Literal["ON", "OFF"] = "OFF"
250
- I_connection: PortReferenceType | None = None
251
- Q_connection: PortReferenceType | None = None
253
+ I_connection: NativeOPXPortType | None = None
254
+ Q_connection: NativeOPXPortType | None = None
252
255
 
253
256
 
254
257
  _RF_SOURCES = Literal[
@@ -270,7 +273,7 @@ class OctaveRFInputConfigType(BaseModel):
270
273
 
271
274
 
272
275
  class OctaveSingleIfOutputConfigType(BaseModel):
273
- port: PortReferenceType | None = None
276
+ port: NativeOPXPortType | None = None
274
277
  name: str | None = None
275
278
 
276
279
 
@@ -279,7 +282,7 @@ class OctaveIfOutputsConfigType(BaseModel):
279
282
  IF_out2: OctaveSingleIfOutputConfigType | None = None
280
283
 
281
284
 
282
- FEM_IDX = Literal[1, 2, 3, 4, 5, 6, 7, 8, "1", "2", "3", "4", "5", "6", "7", "8"]
285
+ FEM_IDX = Annotated[int, Field(ge=1, le=8)]
283
286
 
284
287
 
285
288
  class OPX1000ControllerConfigType(BaseModel):
@@ -296,13 +299,13 @@ LoopbackType = tuple[
296
299
  class OctaveConfig(BaseModel):
297
300
  """Octave configuration for qm-qua 1.1.7."""
298
301
 
299
- RF_outputs: Mapping[IntLike, OctaveRFOutputConfigType] = {}
302
+ RF_outputs: Mapping[int, OctaveRFOutputConfigType] = {}
300
303
  """
301
304
  RF Outputs in Octave's up-converter chain.
302
305
  OPX/AnalogOutput -> Octave/IFInput -> Octave/RFOutput -> Fridge.
303
306
  """
304
307
 
305
- RF_inputs: Mapping[IntLike, OctaveRFInputConfigType] = {}
308
+ RF_inputs: Mapping[int, OctaveRFInputConfigType] = {}
306
309
  """RF Inputs in Octave's down-converter chain. See IF_Outputs."""
307
310
 
308
311
  IF_outputs: OctaveIfOutputsConfigType | None = None
@@ -367,7 +370,7 @@ class OctaveConfig121(OctaveConfig):
367
370
  class DigitalInputConfigType(BaseModel):
368
371
  delay: int | None = None
369
372
  buffer: int | None = None
370
- port: PortReferenceType | None = None
373
+ port: QMPortTypes | None = None
371
374
 
372
375
 
373
376
  class IntegrationWeightConfigType(BaseModel):
@@ -413,16 +416,16 @@ class PulseConfigType(BaseModel):
413
416
 
414
417
 
415
418
  class SingleInputConfigType(BaseModel):
416
- port: PortReferenceType | None = None
419
+ port: QMPortTypes | None = None
417
420
 
418
421
 
419
422
  class MwInputConfigType(BaseModel):
420
- port: PortReferenceType | None = None
421
- upconverter: int | None = None
423
+ port: NativeOPX1000PortType | None = None
424
+ upconverter: int = Field(default=1, description="The index of the upconverter to use.")
422
425
 
423
426
 
424
427
  class MwOutputConfigType(BaseModel):
425
- port: PortReferenceType | None = None
428
+ port: NativeOPX1000PortType | None = None
426
429
 
427
430
 
428
431
  class HoldOffsetConfigType(BaseModel):
@@ -436,14 +439,14 @@ class StickyConfigType(BaseModel):
436
439
 
437
440
 
438
441
  class MixInputConfigType(BaseModel):
439
- I: PortReferenceType | None = None
440
- Q: PortReferenceType | None = None
442
+ I: QMPortTypes | None = None
443
+ Q: QMPortTypes | None = None
441
444
  mixer: str | None = None
442
445
  lo_frequency: float | None = None
443
446
 
444
447
 
445
448
  class InputCollectionConfigType(BaseModel):
446
- inputs: Mapping[str, PortReferenceType] = {}
449
+ inputs: Mapping[str, QMPortTypes] = {}
447
450
 
448
451
 
449
452
  class OscillatorConfigType(BaseModel):
@@ -472,15 +475,15 @@ class ElementConfig(BaseModel):
472
475
  multipleInputs: InputCollectionConfigType | None = None
473
476
  time_of_flight: int | None = None
474
477
  smearing: int | None = None
475
- outputs: Mapping[str, PortReferenceType] = {}
478
+ outputs: Mapping[str, QMPortTypes] = {}
476
479
  digitalInputs: Mapping[str, DigitalInputConfigType] | None = None
477
- digitalOutputs: Mapping[str, PortReferenceType] | None = None
480
+ digitalOutputs: Mapping[str, QMPortTypes] | None = None
478
481
  outputPulseParameters: OutputPulseParameterConfigType | None = None
479
482
  hold_offset: HoldOffsetConfigType | None = None
480
483
  sticky: StickyConfigType | None = None
481
484
  thread: str | None = None
482
- RF_inputs: Mapping[str, tuple[str, int]] | None = None
483
- RF_outputs: Mapping[str, tuple[str, int]] | None = None
485
+ RF_inputs: Mapping[str, NativeOPXPortType] | None = None
486
+ RF_outputs: Mapping[str, NativeOPXPortType] | None = None
484
487
 
485
488
  @model_validator(mode="after")
486
489
  def validator_oscillators(self) -> Self:
@@ -499,7 +502,7 @@ class ElementConfig121(ElementConfig):
499
502
 
500
503
  @model_validator(mode="after")
501
504
  def validate_outputs(self) -> Self:
502
- if self.RF_outputs:
505
+ if self.RF_outputs or self.MWOutput:
503
506
  if self.smearing is None:
504
507
  raise ValueError("Element with output must have smearing defined.")
505
508
  if self.time_of_flight is None:
@@ -529,9 +532,6 @@ class _BaseQuaConfig(BaseModel):
529
532
  qm_version: str
530
533
  """The qm-qua package version used."""
531
534
 
532
- version: str = "1"
533
- """The configuration version. This is a field used in Qua's configuration API."""
534
-
535
535
  oscillators: Mapping[str, OscillatorConfigType] = {}
536
536
  """The oscillators used to drive the elements."""
537
537