boulder-opal-scale-up-sdk 1.0.6__py3-none-any.whl → 1.0.8__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.
- {boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/METADATA +4 -6
- {boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/RECORD +46 -39
- boulderopalscaleupsdk/common/dtypes.py +36 -10
- boulderopalscaleupsdk/device/controller/qblox.py +159 -54
- boulderopalscaleupsdk/device/device.py +0 -1
- boulderopalscaleupsdk/device/processor/superconducting_processor.py +21 -1
- boulderopalscaleupsdk/experiments/chi01_scan.py +1 -1
- boulderopalscaleupsdk/experiments/cz_spectroscopy_by_bias.py +29 -48
- boulderopalscaleupsdk/experiments/drag_leakage_calibration.py +1 -4
- boulderopalscaleupsdk/experiments/fine_amplitude_calibration.py +4 -3
- boulderopalscaleupsdk/experiments/power_rabi.py +3 -3
- boulderopalscaleupsdk/experiments/power_rabi_ef.py +3 -3
- boulderopalscaleupsdk/experiments/ramsey.py +1 -1
- boulderopalscaleupsdk/experiments/ramsey_ef.py +1 -1
- boulderopalscaleupsdk/experiments/readout_classifier.py +2 -2
- boulderopalscaleupsdk/experiments/readout_optimization.py +3 -3
- boulderopalscaleupsdk/experiments/resonator_spectroscopy.py +1 -1
- boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_bias.py +3 -3
- boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_power.py +1 -1
- boulderopalscaleupsdk/experiments/t1.py +1 -1
- boulderopalscaleupsdk/experiments/t2.py +2 -2
- boulderopalscaleupsdk/experiments/t2_echo.py +1 -1
- boulderopalscaleupsdk/experiments/transmon_anharmonicity.py +1 -1
- boulderopalscaleupsdk/experiments/transmon_spectroscopy.py +2 -2
- boulderopalscaleupsdk/experiments/voltage_bias_fine_tune.py +7 -5
- boulderopalscaleupsdk/experiments/waveforms.py +15 -0
- boulderopalscaleupsdk/experiments/zz_ramsey.py +8 -14
- boulderopalscaleupsdk/plotting/dtypes.py +1 -1
- boulderopalscaleupsdk/protobuf/v1/device_pb2.py +33 -39
- boulderopalscaleupsdk/protobuf/v1/device_pb2.pyi +10 -18
- boulderopalscaleupsdk/protobuf/v1/device_pb2_grpc.py +0 -34
- boulderopalscaleupsdk/protobuf/v1/resource_pb2.py +40 -0
- boulderopalscaleupsdk/protobuf/v1/resource_pb2.pyi +52 -0
- boulderopalscaleupsdk/protobuf/v1/resource_pb2_grpc.py +104 -0
- boulderopalscaleupsdk/routines/__init__.py +2 -0
- boulderopalscaleupsdk/routines/coupler_discovery.py +37 -0
- boulderopalscaleupsdk/routines/one_qubit_calibration.py +4 -0
- boulderopalscaleupsdk/routines/resonator_mapping.py +1 -1
- boulderopalscaleupsdk/routines/transmon_retuning.py +0 -4
- boulderopalscaleupsdk/solutions/__init__.py +22 -0
- boulderopalscaleupsdk/solutions/common.py +23 -0
- boulderopalscaleupsdk/solutions/placeholder_solution.py +28 -0
- boulderopalscaleupsdk/third_party/quantum_machines/__init__.py +15 -0
- boulderopalscaleupsdk/third_party/quantum_machines/config.py +0 -3
- {boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/LICENSE +0 -0
- {boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/WHEEL +0 -0
{boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: boulder-opal-scale-up-sdk
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.8
|
4
4
|
Summary: Q-CTRL Boulder Opal Scale Up Python SDK
|
5
5
|
License: https://q-ctrl.com/terms
|
6
6
|
Keywords: black opal,boulder opal,fire opal,nisq,open controls,q control,q ctrl,q-control,q-ctrl,qcontrol,qctrl,quantum,quantum algorithms,quantum circuits,quantum coding,quantum coding software,quantum computing,quantum control,quantum control software,quantum control theory,quantum engineering,quantum error correction,quantum firmware,quantum fundamentals,quantum sensing,qubit,qudit
|
@@ -14,10 +14,8 @@ Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
15
15
|
Classifier: Intended Audience :: Education
|
16
16
|
Classifier: Intended Audience :: Science/Research
|
17
|
-
Classifier: License :: Other/Proprietary License
|
18
17
|
Classifier: Natural Language :: English
|
19
18
|
Classifier: Operating System :: OS Independent
|
20
|
-
Classifier: Programming Language :: Python :: 3
|
21
19
|
Classifier: Programming Language :: Python :: 3.11
|
22
20
|
Classifier: Programming Language :: Python :: 3.12
|
23
21
|
Classifier: Topic :: Internet :: WWW/HTTP
|
@@ -27,13 +25,13 @@ Classifier: Topic :: Software Development :: Embedded Systems
|
|
27
25
|
Classifier: Topic :: System :: Distributed Computing
|
28
26
|
Provides-Extra: quantum-machines
|
29
27
|
Requires-Dist: attrs (>=25.1.0,<26.0.0)
|
30
|
-
Requires-Dist: googleapis-common-protos (>=1.69.2,<
|
31
|
-
Requires-Dist: numpy (>=
|
28
|
+
Requires-Dist: googleapis-common-protos (>=1.69.2,<1.70.0)
|
29
|
+
Requires-Dist: numpy (>=2.3.3,<3.0.0)
|
32
30
|
Requires-Dist: pydantic (>=2.10.4,<3.0.0)
|
33
31
|
Requires-Dist: pydantic-settings (>=2.7.0,<3.0.0)
|
34
32
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
35
33
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
36
|
-
Requires-Dist: qm-qua
|
34
|
+
Requires-Dist: qm-qua ; extra == "quantum-machines"
|
37
35
|
Project-URL: Facebook, https://www.facebook.com/qctrl
|
38
36
|
Project-URL: GitHub, https://github.com/qctrl
|
39
37
|
Project-URL: Homepage, https://q-ctrl.com
|
{boulder_opal_scale_up_sdk-1.0.6.dist-info → boulder_opal_scale_up_sdk-1.0.8.dist-info}/RECORD
RENAMED
@@ -2,7 +2,7 @@ boulderopalscaleupsdk/__init__.py,sha256=nD3YDqPiE52mmuUrIlDUrYSyljpMsDJvc5HsubB
|
|
2
2
|
boulderopalscaleupsdk/agent/__init__.py,sha256=aFkAtHJDOdXA126JklxYz0ix1k4lCcLLS9DQp8zUKMk,1092
|
3
3
|
boulderopalscaleupsdk/agent/worker.py,sha256=mCwVMbWw2saAQKyQuozhEz9JJDwpezesItZim-5qWQ8,9176
|
4
4
|
boulderopalscaleupsdk/common/__init__.py,sha256=vLaJ1FP36xV5eX6VD7nShqxVBm3UzsBMIK1pmSiTIag,550
|
5
|
-
boulderopalscaleupsdk/common/dtypes.py,sha256=
|
5
|
+
boulderopalscaleupsdk/common/dtypes.py,sha256=r5ht75tCHNZUfq7jlmlUVEtKgYFOo1n35zgOWj6n6z8,11639
|
6
6
|
boulderopalscaleupsdk/common/typeclasses.py,sha256=dUpM4vDNQCxVuB45LTyEWO7SuLyzUlG6mJuseM80Chw,3668
|
7
7
|
boulderopalscaleupsdk/constants.py,sha256=2B3LrPH8bAQzzlkRYP5nyIkRT3LmfdIzzxiFKHWICPQ,682
|
8
8
|
boulderopalscaleupsdk/device/__init__.py,sha256=vLaJ1FP36xV5eX6VD7nShqxVBm3UzsBMIK1pmSiTIag,550
|
@@ -10,70 +10,77 @@ boulderopalscaleupsdk/device/common.py,sha256=NxiFdpHXd1Es2_8iqUeAqhL4R4W-POzHoW
|
|
10
10
|
boulderopalscaleupsdk/device/config_loader.py,sha256=kGUaUtYAREYN7grtQ9SUO3dPUqiHVUnVOQbXFZpXvtw,3414
|
11
11
|
boulderopalscaleupsdk/device/controller/__init__.py,sha256=ePkrCbX1ORm05fS0BEQ8cx7DPxGGN6IkUoNH6eQL1DM,1136
|
12
12
|
boulderopalscaleupsdk/device/controller/base.py,sha256=xuT4VzRulknxppiQpzYYn_TwuRNfV9wHMqjN2okA8Lw,793
|
13
|
-
boulderopalscaleupsdk/device/controller/qblox.py,sha256=
|
13
|
+
boulderopalscaleupsdk/device/controller/qblox.py,sha256=1ZsfvUe7Vbu-KZf9W2YluJ1eeUqLWDivFYvd1PvXeDc,33312
|
14
14
|
boulderopalscaleupsdk/device/controller/quantum_machines.py,sha256=dkBSAqdEDADpn-qq7SkiZ-Rfnwh1NLQruqJGEW06ikU,7784
|
15
15
|
boulderopalscaleupsdk/device/controller/resolver.py,sha256=hW5U58dmJf_IGmD4EK_bbn0XU-N9autFBFHmqbRnY2Y,3812
|
16
16
|
boulderopalscaleupsdk/device/defcal.py,sha256=3IPmcLx89ZDv9sCPncozWA-hhnZRZK3OiOiBcAW05lI,739
|
17
|
-
boulderopalscaleupsdk/device/device.py,sha256=
|
17
|
+
boulderopalscaleupsdk/device/device.py,sha256=3IzYd0n_Nus4n5bgZKIraUXWLcsfoThCkjQYG0ZVSZY,2170
|
18
18
|
boulderopalscaleupsdk/device/processor/__init__.py,sha256=YLn1UTCIX0CYfah1muLXrhujJx7sz56JZQ4Pn4DnKd0,972
|
19
19
|
boulderopalscaleupsdk/device/processor/common.py,sha256=rF2mq6X9Zl99mMc5JOqvKZEKCnfA0uUPsrwVWRiIOUA,9661
|
20
|
-
boulderopalscaleupsdk/device/processor/superconducting_processor.py,sha256=
|
20
|
+
boulderopalscaleupsdk/device/processor/superconducting_processor.py,sha256=8rkfvkMIc7wTnqEaRTyl9A-4ds_D-wIXU4Ovgd7YfC8,14371
|
21
21
|
boulderopalscaleupsdk/errors.py,sha256=iN3Y1bQ-GnSLuTCKLG3H1OTbUpW-ibFIEfT3jPuMW48,735
|
22
22
|
boulderopalscaleupsdk/experiments/__init__.py,sha256=zozsQtxhXz1s1cNoUoJ2lQlAOAbp2ozVhquxXw3KrF8,2485
|
23
|
-
boulderopalscaleupsdk/experiments/chi01_scan.py,sha256=
|
23
|
+
boulderopalscaleupsdk/experiments/chi01_scan.py,sha256=L9Xf-01l7uAGwg8FhnqWuG3QmE567meYVUD_0RTWYYI,2290
|
24
24
|
boulderopalscaleupsdk/experiments/common.py,sha256=m-A91hOcLYHBqL9jUI4-ia_13U0-wv711aMgCyjiGqw,2535
|
25
|
-
boulderopalscaleupsdk/experiments/cz_spectroscopy_by_bias.py,sha256=
|
26
|
-
boulderopalscaleupsdk/experiments/drag_leakage_calibration.py,sha256=
|
27
|
-
boulderopalscaleupsdk/experiments/fine_amplitude_calibration.py,sha256=
|
28
|
-
boulderopalscaleupsdk/experiments/power_rabi.py,sha256
|
29
|
-
boulderopalscaleupsdk/experiments/power_rabi_ef.py,sha256=
|
30
|
-
boulderopalscaleupsdk/experiments/ramsey.py,sha256=
|
31
|
-
boulderopalscaleupsdk/experiments/ramsey_ef.py,sha256=
|
32
|
-
boulderopalscaleupsdk/experiments/readout_classifier.py,sha256=
|
33
|
-
boulderopalscaleupsdk/experiments/readout_optimization.py,sha256=
|
34
|
-
boulderopalscaleupsdk/experiments/resonator_spectroscopy.py,sha256=
|
35
|
-
boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_bias.py,sha256=
|
36
|
-
boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_power.py,sha256=
|
37
|
-
boulderopalscaleupsdk/experiments/t1.py,sha256=
|
38
|
-
boulderopalscaleupsdk/experiments/t2.py,sha256=
|
39
|
-
boulderopalscaleupsdk/experiments/t2_echo.py,sha256=
|
40
|
-
boulderopalscaleupsdk/experiments/transmon_anharmonicity.py,sha256=
|
41
|
-
boulderopalscaleupsdk/experiments/transmon_spectroscopy.py,sha256=
|
42
|
-
boulderopalscaleupsdk/experiments/voltage_bias_fine_tune.py,sha256=
|
43
|
-
boulderopalscaleupsdk/experiments/waveforms.py,sha256=
|
44
|
-
boulderopalscaleupsdk/experiments/zz_ramsey.py,sha256=
|
25
|
+
boulderopalscaleupsdk/experiments/cz_spectroscopy_by_bias.py,sha256=Q0bdoBUevHKyuercyZfHTCEkbm2ST0KqE9WeGCrHMfA,2377
|
26
|
+
boulderopalscaleupsdk/experiments/drag_leakage_calibration.py,sha256=JK_GIXIY0GcLGBjEBKwTryfM9ERQVKBBIGIeOyKh2TA,2319
|
27
|
+
boulderopalscaleupsdk/experiments/fine_amplitude_calibration.py,sha256=OZXVtS33eYmpuH30zDl4yycdJMNj99DIj_eTvw3DUlk,2039
|
28
|
+
boulderopalscaleupsdk/experiments/power_rabi.py,sha256=zCMMO4JvyFvzOzpI75_loVN1O6tvEPx_maJ0m7mp0_E,2473
|
29
|
+
boulderopalscaleupsdk/experiments/power_rabi_ef.py,sha256=aEjSzqWORRFt2OZPRD7QzyGJe3vqouAHZcge-N4eZ0Q,2481
|
30
|
+
boulderopalscaleupsdk/experiments/ramsey.py,sha256=Y_vTaod2bateukHx28FAK87puRZXlvgFQd8bz38eZhw,2202
|
31
|
+
boulderopalscaleupsdk/experiments/ramsey_ef.py,sha256=eV98iMqKCXhs4v66H1n-TzvcQl-y711_1-H-btZzndY,2204
|
32
|
+
boulderopalscaleupsdk/experiments/readout_classifier.py,sha256=tEuH5__QTGRPjqUwR5Z6PYZ9skZW592UCH5P-OEkPdw,2000
|
33
|
+
boulderopalscaleupsdk/experiments/readout_optimization.py,sha256=pZffzOzN7iNOd1-iKcfvAivecBTSg4dRsKG0J-oT5yg,1963
|
34
|
+
boulderopalscaleupsdk/experiments/resonator_spectroscopy.py,sha256=aE5vOhCZiAbPUyeKATbGq1499bLk-Dj89XF_5a6HyRc,2272
|
35
|
+
boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_bias.py,sha256=7Aq-VgENmMfGQ7yEz_zW9CaXpCjYdcWxqGK_mXAKewo,2864
|
36
|
+
boulderopalscaleupsdk/experiments/resonator_spectroscopy_by_power.py,sha256=xxe43VHofvmzL715r_8FquGMMYIJkkC2Eu5yOLN5N6A,2393
|
37
|
+
boulderopalscaleupsdk/experiments/t1.py,sha256=bL5ur-0Z3n34pH5Eski_ctv5CI552bup_chRiTWphaw,1645
|
38
|
+
boulderopalscaleupsdk/experiments/t2.py,sha256=Jp3v8aKLIHoFlpEyJVM_aLB_cV8vCj9_2kBWeohSFbs,1800
|
39
|
+
boulderopalscaleupsdk/experiments/t2_echo.py,sha256=tFgOWEjGlhEnLnDvR3v-v92MBQlSqG_dSWHMsrSLWjI,1814
|
40
|
+
boulderopalscaleupsdk/experiments/transmon_anharmonicity.py,sha256=G8ywCKIccHW4XlJYUoNq2bL0L1547G7VAOGjaXaNShY,2811
|
41
|
+
boulderopalscaleupsdk/experiments/transmon_spectroscopy.py,sha256=QFeTRmDE-CM7mIX0GTtVTtg3n-GJ70R1Rl6k9jOAyHU,2412
|
42
|
+
boulderopalscaleupsdk/experiments/voltage_bias_fine_tune.py,sha256=fORNVo2PBs-gwNpOk04nD0uPrKqw7I-IoaC9A4lxDME,2114
|
43
|
+
boulderopalscaleupsdk/experiments/waveforms.py,sha256=zxEQaSaJP10ZHTZS4wqXD4E-sAc-F0l5H6uBiPjibtg,2239
|
44
|
+
boulderopalscaleupsdk/experiments/zz_ramsey.py,sha256=l4cc3xmi1xxvRn-HMt0-9Ff315xGLX8NMkuu-hzEsyU,1780
|
45
45
|
boulderopalscaleupsdk/grpc_interceptors/__init__.py,sha256=PkdOlllLbRWycofvGCCxDY60Ydp_U0QM5l4u3Fsnno4,616
|
46
46
|
boulderopalscaleupsdk/grpc_interceptors/auth.py,sha256=PSe_b9ckqhcb3xf1Y4jpn1TjfEWfokkarqfUHIz6HIs,4165
|
47
47
|
boulderopalscaleupsdk/grpc_interceptors/error.py,sha256=PeEH4eFGFfRNwBw8iDuKVQo02_mItAUVehYa7AiZNqI,12067
|
48
48
|
boulderopalscaleupsdk/plotting/__init__.py,sha256=pkdCky3YHqc3PLRy_h9puJKAO4AqSJGebb26x7XayR4,959
|
49
|
-
boulderopalscaleupsdk/plotting/dtypes.py,sha256=
|
49
|
+
boulderopalscaleupsdk/plotting/dtypes.py,sha256=Qg98_J4dJkz63vZY8Vg_Sz0BfeG0J7bypPiBIFDPmfk,5012
|
50
50
|
boulderopalscaleupsdk/protobuf/v1/agent_pb2.py,sha256=r8vE_d7e5iG04UCDeV0FgxOVOSflOlwmSs2I5CotDBU,6147
|
51
51
|
boulderopalscaleupsdk/protobuf/v1/agent_pb2.pyi,sha256=bwRNbnwbwkqx7OSE4EurVS6865zqdtqmTcRjwJNH7OI,3082
|
52
52
|
boulderopalscaleupsdk/protobuf/v1/agent_pb2_grpc.py,sha256=gfv0Ncc6_MS38Lzj6NHYXhwJVo7qK7XYQiCsi-KTl5w,8593
|
53
|
-
boulderopalscaleupsdk/protobuf/v1/device_pb2.py,sha256=
|
54
|
-
boulderopalscaleupsdk/protobuf/v1/device_pb2.pyi,sha256=
|
55
|
-
boulderopalscaleupsdk/protobuf/v1/device_pb2_grpc.py,sha256=
|
53
|
+
boulderopalscaleupsdk/protobuf/v1/device_pb2.py,sha256=_FhknSKCCb44sR2tKefDVOG7uoaxsKz99DASq69cxAc,12066
|
54
|
+
boulderopalscaleupsdk/protobuf/v1/device_pb2.pyi,sha256=3yJwp1sxVs0bvwiZ58bEX5aNJmKWQWSfEXFJYo6V33k,7559
|
55
|
+
boulderopalscaleupsdk/protobuf/v1/device_pb2_grpc.py,sha256=gHWoNIVcMYx0T7LsbtGNNXIGBMagEgfe-KKbhx5B4I0,19339
|
56
56
|
boulderopalscaleupsdk/protobuf/v1/job_pb2.py,sha256=awz-VTyt6lMJmf8ulW4kxSk-U_pYQOoZAyieww-RvaQ,4737
|
57
57
|
boulderopalscaleupsdk/protobuf/v1/job_pb2.pyi,sha256=C6ygytheTgOohv3bA_CoCFh1Dvqcwwi_1dCsI93kTm4,2354
|
58
58
|
boulderopalscaleupsdk/protobuf/v1/job_pb2_grpc.py,sha256=rwMHUYSaNT8uScrRxwEtR5niA3ghNjqJ6mzKVniBT9Q,6336
|
59
|
+
boulderopalscaleupsdk/protobuf/v1/resource_pb2.py,sha256=kHajKhGXlgFDdalqWZ2OoZj6eTACGKqx-QvtvrzXBzg,4259
|
60
|
+
boulderopalscaleupsdk/protobuf/v1/resource_pb2.pyi,sha256=666p6LTZOIuT_ms9NWBEuKDQoqy-1jIfIp1xktcnkLw,2306
|
61
|
+
boulderopalscaleupsdk/protobuf/v1/resource_pb2_grpc.py,sha256=iE0_cs9JUicHH6R5JM0i12Gygxs03Ag55_N1fYhuOoQ,4669
|
59
62
|
boulderopalscaleupsdk/protobuf/v1/task_pb2.py,sha256=Sd-xzEOJkEZAFw_A0cNXVKOZ_Q71XrIkMl8OTuL9zoo,7132
|
60
63
|
boulderopalscaleupsdk/protobuf/v1/task_pb2.pyi,sha256=o4QeMmUCT_x19eL7dlNE0LtdqJi1e9kv2gMiD7Z4pwg,6048
|
61
64
|
boulderopalscaleupsdk/protobuf/v1/task_pb2_grpc.py,sha256=yP2FZ148RmSYFHivatCXuM13oRBDA5wBwmvhZQNBTXQ,5826
|
62
65
|
boulderopalscaleupsdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
|
-
boulderopalscaleupsdk/routines/__init__.py,sha256=
|
66
|
+
boulderopalscaleupsdk/routines/__init__.py,sha256=4WUUHw681esSf8R3K11AAegBbrRhrD7TgOAdj1PZZq0,1081
|
64
67
|
boulderopalscaleupsdk/routines/common.py,sha256=BvZ1DvCJDFHkauOEq8z-Mkj_mwO-1BSRLHkiTaIbJ0U,775
|
65
|
-
boulderopalscaleupsdk/routines/
|
66
|
-
boulderopalscaleupsdk/routines/
|
68
|
+
boulderopalscaleupsdk/routines/coupler_discovery.py,sha256=8f-zEdO8DoAIsLEP-rJn2f2i4nvD4MJ2Org9lElVPAg,1128
|
69
|
+
boulderopalscaleupsdk/routines/one_qubit_calibration.py,sha256=n6CxupOkQal7-JiOqA81Y5Bsr5u51i5-q0bz-eOfim0,1251
|
70
|
+
boulderopalscaleupsdk/routines/resonator_mapping.py,sha256=FX2zKeeP-UM09OOr9X451-b9sEvDupcUe4tDXxuRPZQ,1196
|
67
71
|
boulderopalscaleupsdk/routines/transmon_coherence.py,sha256=qwFlrDgwRdo4rWwXJoQ0pLJSKiUnzMYasK6kMHWhlHI,1074
|
68
72
|
boulderopalscaleupsdk/routines/transmon_discovery.py,sha256=ZI-mQQSlUWhU1J_H1ie9Hz4TOK3aMxZqtfX2AgHNrKI,1453
|
69
|
-
boulderopalscaleupsdk/routines/transmon_retuning.py,sha256=
|
73
|
+
boulderopalscaleupsdk/routines/transmon_retuning.py,sha256=sCt__KrabNupd5dJJAcZqk6Jf026r_cN4wm1lJ3YwWs,1239
|
74
|
+
boulderopalscaleupsdk/solutions/__init__.py,sha256=4aNTanH2A7QBvkilWYYpdeGZiUssgbqdLbP2rAyLUX4,717
|
75
|
+
boulderopalscaleupsdk/solutions/common.py,sha256=4IxWr2sXWYms1K4c460FQ129nlljF9ryJ_oNUQkV9xQ,779
|
76
|
+
boulderopalscaleupsdk/solutions/placeholder_solution.py,sha256=lWP9uNW_AnuPEwbHSl1psdqlYchWvfDSceF612taP9o,907
|
70
77
|
boulderopalscaleupsdk/third_party/__init__.py,sha256=b9T2IVfz9bMenSsLQuaf4A14ySinjNnSGx68hLsFHZE,596
|
71
|
-
boulderopalscaleupsdk/third_party/quantum_machines/__init__.py,sha256=
|
72
|
-
boulderopalscaleupsdk/third_party/quantum_machines/config.py,sha256=
|
78
|
+
boulderopalscaleupsdk/third_party/quantum_machines/__init__.py,sha256=D-6LLQacjr4fBNb4AvF-caQtozOoKiJsv6LuMBUNHEE,3195
|
79
|
+
boulderopalscaleupsdk/third_party/quantum_machines/config.py,sha256=LSLmZRbOa8DXqSvXKL0y8mEsNxoRHOdr3i3pYXafjdY,20656
|
73
80
|
boulderopalscaleupsdk/third_party/quantum_machines/constants.py,sha256=5PpAi6MZ53yEinBHerY2ssi30BR37JnLBWL21irpZ8Y,870
|
74
81
|
boulderopalscaleupsdk/utils/__init__.py,sha256=vLaJ1FP36xV5eX6VD7nShqxVBm3UzsBMIK1pmSiTIag,550
|
75
82
|
boulderopalscaleupsdk/utils/serial_utils.py,sha256=SzvY-WFD0b8IGSh6PTv7F9y1W2IPPYmj8pY3AsX-xlM,2062
|
76
|
-
boulder_opal_scale_up_sdk-1.0.
|
77
|
-
boulder_opal_scale_up_sdk-1.0.
|
78
|
-
boulder_opal_scale_up_sdk-1.0.
|
79
|
-
boulder_opal_scale_up_sdk-1.0.
|
83
|
+
boulder_opal_scale_up_sdk-1.0.8.dist-info/LICENSE,sha256=wqX4S5Brcwkwo750l9grSspwm0cyMsZtZEa1Vx3_WiE,36587
|
84
|
+
boulder_opal_scale_up_sdk-1.0.8.dist-info/METADATA,sha256=DXWuUYplUMJ_Vr9UirCcED-gLLAqrV7MTCf-zY3ow7k,2312
|
85
|
+
boulder_opal_scale_up_sdk-1.0.8.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
86
|
+
boulder_opal_scale_up_sdk-1.0.8.dist-info/RECORD,,
|
@@ -33,7 +33,7 @@ from dateutil.parser import isoparse
|
|
33
33
|
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, PlainSerializer, TypeAdapter
|
34
34
|
from pydantic.dataclasses import dataclass
|
35
35
|
|
36
|
-
from boulderopalscaleupsdk.plotting
|
36
|
+
from boulderopalscaleupsdk.plotting import Plot
|
37
37
|
|
38
38
|
GrpcMetadata = list[tuple[str, str | bytes]]
|
39
39
|
|
@@ -158,7 +158,7 @@ class Duration:
|
|
158
158
|
|
159
159
|
self.value = int(self.value)
|
160
160
|
try:
|
161
|
-
self._np_rep = np.timedelta64(self.value, self.unit)
|
161
|
+
self._np_rep = np.timedelta64(self.value, self.unit.value)
|
162
162
|
except ValueError as e:
|
163
163
|
raise err from e
|
164
164
|
|
@@ -179,12 +179,17 @@ class Duration:
|
|
179
179
|
return bool(self._np_rep == other._np_rep)
|
180
180
|
return False
|
181
181
|
|
182
|
-
def
|
183
|
-
|
182
|
+
def __str__(self):
|
183
|
+
return f"{self.value} {self.unit.value}"
|
184
|
+
|
185
|
+
def convert(self, unit: TimeUnit | str) -> Duration | InvalidDurationConversion:
|
186
|
+
unit_enum = TimeUnit(unit) if isinstance(unit, str) else unit
|
187
|
+
|
188
|
+
val = np.float64(self._np_rep / np.timedelta64(1, unit_enum.value))
|
184
189
|
if val.is_integer():
|
185
|
-
return Duration(int(val),
|
190
|
+
return Duration(int(val), unit_enum)
|
186
191
|
return InvalidDurationConversion(
|
187
|
-
f"fail to convert to {
|
192
|
+
f"fail to convert to {unit_enum} with {self.value} {self.unit}.",
|
188
193
|
)
|
189
194
|
|
190
195
|
def to_ns(self) -> Duration:
|
@@ -342,14 +347,17 @@ class JobSummary(BaseModel):
|
|
342
347
|
|
343
348
|
class JobDataEntry(BaseModel):
|
344
349
|
message: str
|
345
|
-
created_at: ISO8601DatetimeUTCLike
|
346
|
-
dt: str
|
347
|
-
elapsed_time: str
|
348
|
-
plots: list[Plot] = []
|
349
350
|
|
350
351
|
class Config:
|
351
352
|
extra = "allow"
|
352
353
|
|
354
|
+
def get_display_items(self) -> list[str | Plot]:
|
355
|
+
items: list[str | Plot] = [self.message]
|
356
|
+
|
357
|
+
if plots := getattr(self, "plots", []):
|
358
|
+
items.extend(TypeAdapter(Plot).validate_python(plot) for plot in plots)
|
359
|
+
return items
|
360
|
+
|
353
361
|
|
354
362
|
class JobData(BaseModel):
|
355
363
|
id: str
|
@@ -359,6 +367,24 @@ class JobData(BaseModel):
|
|
359
367
|
device_name: str
|
360
368
|
data: list[JobDataEntry]
|
361
369
|
|
370
|
+
def get_display_items(self) -> list[str | Plot]:
|
371
|
+
items: list[str | Plot] = []
|
372
|
+
message = "\n".join(
|
373
|
+
[
|
374
|
+
"JobData summary:",
|
375
|
+
f" - id: {self.id}",
|
376
|
+
f" - name: {self.name}",
|
377
|
+
f" - session_id: {self.session_id}",
|
378
|
+
f" - created_at: {self.created_at.isoformat()}",
|
379
|
+
f" - device_name: {self.device_name}",
|
380
|
+
],
|
381
|
+
)
|
382
|
+
items.append(message)
|
383
|
+
|
384
|
+
for job_data_entry in self.data:
|
385
|
+
items.extend(job_data_entry.get_display_items())
|
386
|
+
return items
|
387
|
+
|
362
388
|
|
363
389
|
DEFAULT_JOB_HISTORY_PAGE = 1
|
364
390
|
DEFAULT_JOB_HISTORY_PAGE_SIZE = 10
|
@@ -20,7 +20,8 @@ __all__ = (
|
|
20
20
|
"AcquisitionConfig",
|
21
21
|
"BitStrideArrayEncoding",
|
22
22
|
"ChannelType",
|
23
|
-
"
|
23
|
+
"IQChannel",
|
24
|
+
"IQMixedChannel",
|
24
25
|
"IndexedData",
|
25
26
|
"ModuleAddr",
|
26
27
|
"ModuleAddrType",
|
@@ -37,11 +38,11 @@ __all__ = (
|
|
37
38
|
"PortAddrType",
|
38
39
|
"PreparedProgram",
|
39
40
|
"PreparedSequenceProgram",
|
40
|
-
"RealChannel",
|
41
41
|
"SequenceProgram",
|
42
42
|
"SequencerAddr",
|
43
43
|
"SequencerAddrType",
|
44
44
|
"SequencerResults",
|
45
|
+
"SingleChannel",
|
45
46
|
"process_sequencer_output",
|
46
47
|
"validate_channel",
|
47
48
|
)
|
@@ -54,7 +55,7 @@ from dataclasses import dataclass
|
|
54
55
|
from typing import Annotated, Any, ClassVar, Literal, Self, TypeVar
|
55
56
|
|
56
57
|
import numpy as np
|
57
|
-
from pydantic import BaseModel, BeforeValidator, Field, PlainSerializer, model_validator
|
58
|
+
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, PlainSerializer, model_validator
|
58
59
|
|
59
60
|
from boulderopalscaleupsdk.device.controller.base import Backend, ControllerType
|
60
61
|
|
@@ -204,10 +205,20 @@ PortAddrType = Annotated[PortAddr, _addr_validator(PortAddr), PlainSerializer(st
|
|
204
205
|
# ==================================================================================================
|
205
206
|
# Signalling Channels
|
206
207
|
# ==================================================================================================
|
207
|
-
class
|
208
|
-
"""
|
208
|
+
class IQMixedChannel(BaseModel):
|
209
|
+
"""
|
210
|
+
An IQ-mixed channel.
|
211
|
+
|
212
|
+
Both sequencer AWG paths are mixed internally and routed to a single module port.
|
213
|
+
|
214
|
+
┌─────────┐Path 0 Port
|
215
|
+
│ ├───────►│IQMixed ┌─┐
|
216
|
+
│Sequencer│ │───────►│─│
|
217
|
+
│ ├───────►│Ch └─┘
|
218
|
+
└─────────┘Path 1
|
219
|
+
"""
|
209
220
|
|
210
|
-
mode: Literal["
|
221
|
+
mode: Literal["iq-mixed"] = "iq-mixed"
|
211
222
|
port: PortAddrType
|
212
223
|
|
213
224
|
@property
|
@@ -219,13 +230,26 @@ class RealChannel(BaseModel):
|
|
219
230
|
return self.port.direction
|
220
231
|
|
221
232
|
def __str__(self) -> str:
|
222
|
-
return f"{self.port!s}[
|
233
|
+
return f"{self.port!s}[1]"
|
234
|
+
|
223
235
|
|
236
|
+
class IQChannel(BaseModel):
|
237
|
+
"""
|
238
|
+
An IQ channel.
|
224
239
|
|
225
|
-
|
226
|
-
"""A Complex channel targeting a single hardware port on a QBLOX module."""
|
240
|
+
The sequencer AWG paths target separate ports for external IQ mixing.
|
227
241
|
|
228
|
-
|
242
|
+
IPort
|
243
|
+
┌─────────┐Path 0 ┌─┐
|
244
|
+
│ ├───────►├───────►│─│
|
245
|
+
│Sequencer│ │IQ Ch ├─┤
|
246
|
+
│ ├───────►├───────►│─│
|
247
|
+
└─────────┘Path 1 └─┘
|
248
|
+
QPort
|
249
|
+
|
250
|
+
"""
|
251
|
+
|
252
|
+
mode: Literal["iq"] = "iq"
|
229
253
|
i_port: PortAddrType
|
230
254
|
q_port: PortAddrType
|
231
255
|
|
@@ -238,10 +262,10 @@ class ComplexChannel(BaseModel):
|
|
238
262
|
return self.i_port.direction
|
239
263
|
|
240
264
|
def __str__(self) -> str:
|
241
|
-
return f"{self.i_port!s}_{self.q_port.number}[
|
265
|
+
return f"{self.i_port!s}_{self.q_port.number}[iq]"
|
242
266
|
|
243
267
|
@model_validator(mode="after")
|
244
|
-
def validate_i_q_ports(self) -> "
|
268
|
+
def validate_i_q_ports(self) -> "IQChannel":
|
245
269
|
ii = self.i_port
|
246
270
|
qq = self.q_port
|
247
271
|
if ii.cluster != qq.cluster or ii.slot != qq.slot:
|
@@ -251,7 +275,36 @@ class ComplexChannel(BaseModel):
|
|
251
275
|
return self
|
252
276
|
|
253
277
|
|
254
|
-
|
278
|
+
class SingleChannel(BaseModel):
|
279
|
+
"""
|
280
|
+
Single channel.
|
281
|
+
|
282
|
+
A single sequencer path is routed to a single port.
|
283
|
+
|
284
|
+
┌─────────┐Path 0 Port
|
285
|
+
│ ├───────►│Single ┌─┐
|
286
|
+
│Sequencer│ ├───────►│─│
|
287
|
+
│ │ │Ch └─┘
|
288
|
+
└─────────┘
|
289
|
+
"""
|
290
|
+
|
291
|
+
mode: Literal["single"] = "single"
|
292
|
+
port: PortAddrType
|
293
|
+
path: Literal[0, 1] = 0
|
294
|
+
|
295
|
+
@property
|
296
|
+
def module(self) -> ModuleAddr:
|
297
|
+
return ModuleAddr(self.port.cluster, self.port.slot)
|
298
|
+
|
299
|
+
@property
|
300
|
+
def direction(self) -> Literal["out", "in"]:
|
301
|
+
return self.port.direction
|
302
|
+
|
303
|
+
def __str__(self) -> str:
|
304
|
+
return f"{self.port!s}_{self.port.number}[single]"
|
305
|
+
|
306
|
+
|
307
|
+
ChannelType = IQMixedChannel | IQChannel | SingleChannel
|
255
308
|
|
256
309
|
|
257
310
|
# ==================================================================================================
|
@@ -318,12 +371,28 @@ class QBLOXControllerInfo(BaseModel): # pragma: no cover
|
|
318
371
|
modules: dict[ModuleAddrType, ModuleType]
|
319
372
|
port_config: dict[str, PortConnection]
|
320
373
|
|
374
|
+
@model_validator(mode="after")
|
375
|
+
def validate_channels(self) -> Self:
|
376
|
+
for port, port_conn in self.port_config.items():
|
377
|
+
mod_addr = port_conn.ch_out.module
|
378
|
+
mod_type = self.modules[mod_addr]
|
379
|
+
|
380
|
+
mod_constraints = DEFAULT_MODULE_CONSTRAINTS[mod_type]
|
381
|
+
if ch_iss := validate_channel(port_conn.ch_out, mod_constraints):
|
382
|
+
raise ValueError(f"Invalid channel for port {port}: {ch_iss}")
|
383
|
+
if port_conn.ch_in and (ch_iss := validate_channel(port_conn.ch_in, mod_constraints)):
|
384
|
+
raise ValueError(f"Invalid channel for port {port}: {ch_iss}")
|
385
|
+
|
386
|
+
return self
|
387
|
+
|
321
388
|
|
322
389
|
# ==================================================================================================
|
323
390
|
# Instrument management
|
324
391
|
# ==================================================================================================
|
325
392
|
class SequencerParams(BaseModel):
|
326
|
-
|
393
|
+
model_config = ConfigDict(validate_assignment=True)
|
394
|
+
|
395
|
+
nco_freq: float | None = Field(default=None, ge=-500e6, le=500e6)
|
327
396
|
gain_awg_path0: float | None = Field(default=None, ge=-1.0, le=1.0)
|
328
397
|
offset_awg_path0: float | None = Field(default=None, ge=-1.0, le=1.0)
|
329
398
|
gain_awg_path1: float | None = Field(default=None, ge=-1.0, le=1.0)
|
@@ -338,6 +407,8 @@ class SequencerParams(BaseModel):
|
|
338
407
|
|
339
408
|
|
340
409
|
class QcmParams(BaseModel):
|
410
|
+
model_config = ConfigDict(validate_assignment=True)
|
411
|
+
|
341
412
|
out0_offset: float | None = Field(default=None, ge=-2.5, le=2.5)
|
342
413
|
out1_offset: float | None = Field(default=None, ge=-2.5, le=2.5)
|
343
414
|
out2_offset: float | None = Field(default=None, ge=-2.5, le=2.5)
|
@@ -354,6 +425,8 @@ class QcmParams(BaseModel):
|
|
354
425
|
|
355
426
|
|
356
427
|
class QcmRfParams(BaseModel):
|
428
|
+
model_config = ConfigDict(validate_assignment=True)
|
429
|
+
|
357
430
|
out0_att: int | None = Field(default=None, ge=0, le=60, multiple_of=2)
|
358
431
|
out1_att: int | None = Field(default=None, ge=0, le=60, multiple_of=2)
|
359
432
|
|
@@ -375,6 +448,8 @@ class QcmRfParams(BaseModel):
|
|
375
448
|
|
376
449
|
|
377
450
|
class QrmRfParams(BaseModel):
|
451
|
+
model_config = ConfigDict(validate_assignment=True)
|
452
|
+
|
378
453
|
out0_att: int | None = Field(default=None, ge=0, le=60, multiple_of=2)
|
379
454
|
|
380
455
|
out0_in0_lo_freq: float | None = Field(default=None, gt=0)
|
@@ -744,6 +819,9 @@ class BitStrideArrayEncoding:
|
|
744
819
|
# ==================================================================================================
|
745
820
|
# Utilities
|
746
821
|
# ==================================================================================================
|
822
|
+
Q1_MAX_WAVEFORM_MEMORY = 16384 # samples
|
823
|
+
|
824
|
+
|
747
825
|
@dataclasses.dataclass
|
748
826
|
class ModuleConstraints:
|
749
827
|
"""Physical constraints of a module."""
|
@@ -753,6 +831,7 @@ class ModuleConstraints:
|
|
753
831
|
n_ch_out: int = 0
|
754
832
|
n_ch_in: int = 0
|
755
833
|
n_digital_io: int = 0
|
834
|
+
is_rf: bool = False
|
756
835
|
|
757
836
|
# TODO: Confirm if ordering is important.
|
758
837
|
ch_out_iq_pairs: list[set[int]] = dataclasses.field(default_factory=list)
|
@@ -773,6 +852,7 @@ DEFAULT_MODULE_CONSTRAINTS: dict[ModuleType, ModuleConstraints] = {
|
|
773
852
|
n_markers=2,
|
774
853
|
n_ch_out=2,
|
775
854
|
n_ch_in=0,
|
855
|
+
is_rf=True,
|
776
856
|
),
|
777
857
|
ModuleType.QRM: ModuleConstraints(
|
778
858
|
n_sequencers=6,
|
@@ -787,6 +867,7 @@ DEFAULT_MODULE_CONSTRAINTS: dict[ModuleType, ModuleConstraints] = {
|
|
787
867
|
n_markers=2,
|
788
868
|
n_ch_out=1,
|
789
869
|
n_ch_in=1,
|
870
|
+
is_rf=True,
|
790
871
|
),
|
791
872
|
ModuleType.QRC: ModuleConstraints(
|
792
873
|
n_sequencers=12,
|
@@ -835,53 +916,77 @@ def validate_channel(ch: ChannelType, constraint: ModuleConstraints) -> list[str
|
|
835
916
|
return _validate_input_channel(ch, constraint)
|
836
917
|
|
837
918
|
|
838
|
-
def _validate_output_channel(ch_out: ChannelType, constraint: ModuleConstraints) -> list[str]:
|
919
|
+
def _validate_output_channel(ch_out: ChannelType, constraint: ModuleConstraints) -> list[str]: # noqa: C901
|
839
920
|
issues = []
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
f"output port number {po_out.number} out-of-bounds for module, "
|
847
|
-
f"must be between [0, {constraint.n_ch_out}).",
|
848
|
-
)
|
849
|
-
else:
|
850
|
-
valid_pairs = constraint.ch_out_iq_pairs
|
851
|
-
if not valid_pairs:
|
852
|
-
issues.append("module does not support complex output channels.")
|
853
|
-
else:
|
854
|
-
po_out_i = ch_out.i_port
|
855
|
-
po_out_q = ch_out.q_port
|
856
|
-
if {po_out_i.number, po_out_q.number} not in valid_pairs:
|
921
|
+
match ch_out:
|
922
|
+
case IQMixedChannel():
|
923
|
+
po_out = ch_out.port
|
924
|
+
if constraint.n_ch_out == 0:
|
925
|
+
issues.append("module has no output ports.")
|
926
|
+
elif po_out.number < 0 or po_out.number >= constraint.n_ch_out:
|
857
927
|
issues.append(
|
858
|
-
f"
|
859
|
-
f"
|
928
|
+
f"output port number {po_out.number} out-of-bounds for module, "
|
929
|
+
f"must be between [0, {constraint.n_ch_out}).",
|
930
|
+
)
|
931
|
+
case IQChannel():
|
932
|
+
valid_pairs = constraint.ch_out_iq_pairs
|
933
|
+
if not valid_pairs:
|
934
|
+
issues.append("module does not support IQ output channels.")
|
935
|
+
else:
|
936
|
+
po_out_i = ch_out.i_port
|
937
|
+
po_out_q = ch_out.q_port
|
938
|
+
if {po_out_i.number, po_out_q.number} not in valid_pairs:
|
939
|
+
issues.append(
|
940
|
+
f"invalid output IQ pair {{{po_out_i.number}, {po_out_q.number}}}, "
|
941
|
+
f"module only supports pairs {valid_pairs}.",
|
942
|
+
)
|
943
|
+
case SingleChannel():
|
944
|
+
po_out = ch_out.port
|
945
|
+
if constraint.is_rf:
|
946
|
+
issues.append("RF modules cannot use single channels.")
|
947
|
+
if constraint.n_ch_out == 0:
|
948
|
+
issues.append("module has no output ports.")
|
949
|
+
elif po_out.number < 0 or po_out.number >= constraint.n_ch_out:
|
950
|
+
issues.append(
|
951
|
+
f"output port number {po_out.number} out-of-bounds for module, "
|
952
|
+
f"must be between [0, {constraint.n_ch_out}).",
|
860
953
|
)
|
861
954
|
return issues
|
862
955
|
|
863
956
|
|
864
|
-
def _validate_input_channel(ch_in: ChannelType, constraint: ModuleConstraints) -> list[str]:
|
957
|
+
def _validate_input_channel(ch_in: ChannelType, constraint: ModuleConstraints) -> list[str]: # noqa: C901
|
865
958
|
issues = []
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
959
|
+
match ch_in:
|
960
|
+
case IQMixedChannel():
|
961
|
+
po_in = ch_in.port
|
962
|
+
if constraint.n_ch_in == 0:
|
963
|
+
issues.append("module has no input ports.")
|
964
|
+
elif po_in.number < 0 or po_in.number >= constraint.n_ch_in:
|
965
|
+
issues.append(
|
966
|
+
f"input port number {po_in.number} out-of-bounds for module, "
|
967
|
+
f"must be between [0, {constraint.n_ch_in}).",
|
968
|
+
)
|
969
|
+
case IQChannel():
|
970
|
+
valid_pairs = constraint.ch_in_iq_pairs
|
971
|
+
if not valid_pairs:
|
972
|
+
issues.append("module does not support IQ input channels.")
|
973
|
+
else:
|
974
|
+
po_in_i = ch_in.i_port
|
975
|
+
po_in_q = ch_in.q_port
|
976
|
+
if {po_in_i.number, po_in_q.number} not in valid_pairs:
|
977
|
+
issues.append(
|
978
|
+
f"invalid input IQ pair {{{po_in_i.number}, {po_in_q.number}}}, "
|
979
|
+
f"module only supports pairs {valid_pairs}.",
|
980
|
+
)
|
981
|
+
case SingleChannel():
|
982
|
+
po_in = ch_in.port
|
983
|
+
if constraint.is_rf:
|
984
|
+
issues.append("RF modules cannot use single channels.")
|
985
|
+
if constraint.n_ch_in == 0:
|
986
|
+
issues.append("module has no input ports.")
|
987
|
+
elif po_in.number < 0 or po_in.number >= constraint.n_ch_in:
|
883
988
|
issues.append(
|
884
|
-
f"
|
885
|
-
f"
|
989
|
+
f"input port number {po_in.number} out-of-bounds for module, "
|
990
|
+
f"must be between [0, {constraint.n_ch_in}).",
|
886
991
|
)
|
887
992
|
return issues
|