-
-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathfomac.cpp
More file actions
499 lines (404 loc) · 21.3 KB
/
Copy pathfomac.cpp
File metadata and controls
499 lines (404 loc) · 21.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/
#include "fomac/FoMaC.hpp"
#include "../../include/mqt-core/qdmi/driver/Driver.hpp"
#include <nanobind/nanobind.h>
#include <nanobind/operators.h>
#include <nanobind/stl/complex.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/map.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/optional.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/pair.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/string.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/vector.h> // NOLINT(misc-include-cleaner)
#include <optional>
#include <qdmi/client.h>
#include <string>
#include <utility>
#include <vector>
namespace mqt {
namespace nb = nanobind;
using namespace nb::literals;
NB_MODULE(MQT_CORE_MODULE_NAME, m) {
// Session class
auto session = nb::class_<fomac::Session>(
m, "Session", R"pb(A FoMaC session for managing QDMI devices.
Allows creating isolated sessions with independent authentication settings.
All authentication parameters are optional and can be provided as keyword arguments to the constructor.)pb");
session.def(
"__init__",
[](fomac::Session* self, std::optional<std::string> token,
std::optional<std::string> authFile,
std::optional<std::string> authUrl,
std::optional<std::string> username,
std::optional<std::string> password,
std::optional<std::string> projectId,
std::optional<std::string> custom1, std::optional<std::string> custom2,
std::optional<std::string> custom3, std::optional<std::string> custom4,
std::optional<std::string> custom5) {
const fomac::SessionConfig config{.token = std::move(token),
.authFile = std::move(authFile),
.authUrl = std::move(authUrl),
.username = std::move(username),
.password = std::move(password),
.projectId = std::move(projectId),
.custom1 = std::move(custom1),
.custom2 = std::move(custom2),
.custom3 = std::move(custom3),
.custom4 = std::move(custom4),
.custom5 = std::move(custom5)};
new (self) fomac::Session(config);
},
nb::kw_only(), "token"_a = std::nullopt, "auth_file"_a = std::nullopt,
"auth_url"_a = std::nullopt, "username"_a = std::nullopt,
"password"_a = std::nullopt, "project_id"_a = std::nullopt,
"custom1"_a = std::nullopt, "custom2"_a = std::nullopt,
"custom3"_a = std::nullopt, "custom4"_a = std::nullopt,
"custom5"_a = std::nullopt,
R"pb(Create a new FoMaC session with optional authentication.
Args:
token: Authentication token
auth_file: Path to file containing authentication information
auth_url: URL to authentication server
username: Username for authentication
password: Password for authentication
project_id: Project ID for session
custom1: Custom configuration parameter 1
custom2: Custom configuration parameter 2
custom3: Custom configuration parameter 3
custom4: Custom configuration parameter 4
custom5: Custom configuration parameter 5
Raises:
RuntimeError: If auth_file does not exist
RuntimeError: If auth_url has invalid format
Example:
>>> from mqt.core.fomac import Session
>>> # Session without authentication
>>> session = Session()
>>> devices = session.get_devices()
>>>
>>> # Session with token authentication
>>> session = Session(token="my_secret_token")
>>> devices = session.get_devices()
>>>
>>> # Session with file-based authentication
>>> session = Session(auth_file="/path/to/auth.json")
>>> devices = session.get_devices()
>>>
>>> # Session with multiple parameters
>>> session = Session(
... auth_url="https://auth.example.com", username="user", password="pass", project_id="project-123"
... )
>>> devices = session.get_devices())pb");
session.def("get_devices", &fomac::Session::getDevices,
nb::rv_policy::reference_internal,
R"pb(Get available devices from this session.
Returns:
List of available devices.)pb");
// Job class
auto job = nb::class_<fomac::Session::Job>(
m, "Job", "A job represents a submitted quantum program execution.");
job.def("check", &fomac::Session::Job::check,
"Returns the current status of the job.");
job.def("wait", &fomac::Session::Job::wait, "timeout"_a = 0,
R"pb(Waits for the job to complete.
Args:
timeout: The maximum time to wait in seconds. If 0, waits indefinitely.
Returns:
True if the job completed within the timeout, False otherwise.)pb");
job.def("cancel", &fomac::Session::Job::cancel, "Cancels the job.");
job.def("get_shots", &fomac::Session::Job::getShots,
"Returns the raw shot results from the job.");
job.def("get_counts", &fomac::Session::Job::getCounts,
"Returns the measurement counts from the job.");
job.def("get_dense_statevector", &fomac::Session::Job::getDenseStateVector,
"Returns the dense statevector from the job (typically only "
"available from simulator devices).");
job.def("get_dense_probabilities",
&fomac::Session::Job::getDenseProbabilities,
"Returns the dense probabilities from the job (typically only "
"available from simulator devices).");
job.def("get_sparse_statevector", &fomac::Session::Job::getSparseStateVector,
"Returns the sparse statevector from the job (typically only "
"available from simulator devices).");
job.def("get_sparse_probabilities",
&fomac::Session::Job::getSparseProbabilities,
"Returns the sparse probabilities from the job (typically only "
"available from simulator devices).");
job.def_prop_ro("id", &fomac::Session::Job::getId, "Returns the job ID.");
job.def_prop_ro("program_format", &fomac::Session::Job::getProgramFormat,
"Returns the program format used for the job.");
job.def_prop_ro("program", &fomac::Session::Job::getProgram,
"Returns the quantum program submitted for the job.");
job.def_prop_ro("num_shots", &fomac::Session::Job::getNumShots,
"Returns the number of shots for the job.");
job.def(nb::self == nb::self,
nb::sig("def __eq__(self, arg: object, /) -> bool"));
job.def(nb::self != nb::self,
nb::sig("def __ne__(self, arg: object, /) -> bool"));
// JobStatus enum
nb::enum_<QDMI_Job_Status>(job, "Status", "Enumeration of job status.")
.value("CREATED", QDMI_JOB_STATUS_CREATED)
.value("SUBMITTED", QDMI_JOB_STATUS_SUBMITTED)
.value("QUEUED", QDMI_JOB_STATUS_QUEUED)
.value("RUNNING", QDMI_JOB_STATUS_RUNNING)
.value("DONE", QDMI_JOB_STATUS_DONE)
.value("CANCELED", QDMI_JOB_STATUS_CANCELED)
.value("FAILED", QDMI_JOB_STATUS_FAILED);
// ProgramFormat enum
nb::enum_<QDMI_Program_Format>(m, "ProgramFormat",
"Enumeration of program formats.")
.value("QASM2", QDMI_PROGRAM_FORMAT_QASM2)
.value("QASM3", QDMI_PROGRAM_FORMAT_QASM3)
.value("QIR_BASE_STRING", QDMI_PROGRAM_FORMAT_QIRBASESTRING)
.value("QIR_BASE_MODULE", QDMI_PROGRAM_FORMAT_QIRBASEMODULE)
.value("QIR_ADAPTIVE_STRING", QDMI_PROGRAM_FORMAT_QIRADAPTIVESTRING)
.value("QIR_ADAPTIVE_MODULE", QDMI_PROGRAM_FORMAT_QIRADAPTIVEMODULE)
.value("CALIBRATION", QDMI_PROGRAM_FORMAT_CALIBRATION)
.value("QPY", QDMI_PROGRAM_FORMAT_QPY)
.value("IQM_JSON", QDMI_PROGRAM_FORMAT_IQMJSON)
.value("CUSTOM1", QDMI_PROGRAM_FORMAT_CUSTOM1)
.value("CUSTOM2", QDMI_PROGRAM_FORMAT_CUSTOM2)
.value("CUSTOM3", QDMI_PROGRAM_FORMAT_CUSTOM3)
.value("CUSTOM4", QDMI_PROGRAM_FORMAT_CUSTOM4)
.value("CUSTOM5", QDMI_PROGRAM_FORMAT_CUSTOM5);
// Device class
auto device = nb::class_<fomac::Session::Device>(
m, "Device",
"A device represents a quantum device with its properties and "
"capabilities.");
nb::enum_<QDMI_Device_Status>(device, "Status",
"Enumeration of device status.")
.value("OFFLINE", QDMI_DEVICE_STATUS_OFFLINE)
.value("IDLE", QDMI_DEVICE_STATUS_IDLE)
.value("BUSY", QDMI_DEVICE_STATUS_BUSY)
.value("ERROR", QDMI_DEVICE_STATUS_ERROR)
.value("MAINTENANCE", QDMI_DEVICE_STATUS_MAINTENANCE)
.value("CALIBRATION", QDMI_DEVICE_STATUS_CALIBRATION);
device.def("name", &fomac::Session::Device::getName,
"Returns the name of the device.");
device.def("version", &fomac::Session::Device::getVersion,
"Returns the version of the device.");
device.def("status", &fomac::Session::Device::getStatus,
"Returns the current status of the device.");
device.def("library_version", &fomac::Session::Device::getLibraryVersion,
"Returns the version of the library used to define the device.");
device.def("qubits_num", &fomac::Session::Device::getQubitsNum,
"Returns the number of qubits available on the device.");
device.def("sites", &fomac::Session::Device::getSites,
"Returns the list of all sites (zone and regular sites) available "
"on the device.");
device.def("regular_sites", &fomac::Session::Device::getRegularSites,
"Returns the list of regular sites (without zone sites) available "
"on the device.");
device.def("zones", &fomac::Session::Device::getZones,
"Returns the list of zone sites (without regular sites) available "
"on the device.");
device.def("operations", &fomac::Session::Device::getOperations,
"Returns the list of operations supported by the device.");
device.def("coupling_map", &fomac::Session::Device::getCouplingMap,
"Returns the coupling map of the device as a list of site pairs.");
device.def("needs_calibration", &fomac::Session::Device::getNeedsCalibration,
"Returns whether the device needs calibration.");
device.def("length_unit", &fomac::Session::Device::getLengthUnit,
"Returns the unit of length used by the device.");
device.def("length_scale_factor",
&fomac::Session::Device::getLengthScaleFactor,
"Returns the scale factor for length used by the device.");
device.def("duration_unit", &fomac::Session::Device::getDurationUnit,
"Returns the unit of duration used by the device.");
device.def("duration_scale_factor",
&fomac::Session::Device::getDurationScaleFactor,
"Returns the scale factor for duration used by the device.");
device.def("min_atom_distance", &fomac::Session::Device::getMinAtomDistance,
"Returns the minimum atom distance on the device.");
device.def("supported_program_formats",
&fomac::Session::Device::getSupportedProgramFormats,
"Returns the list of program formats supported by the device.");
device.def("submit_job", &fomac::Session::Device::submitJob, "program"_a,
"program_format"_a, "num_shots"_a,
nb::rv_policy::reference_internal, "Submits a job to the device.");
device.def("__repr__", [](const fomac::Session::Device& dev) {
return "<Device name=\"" + dev.getName() + "\">";
});
device.def(nb::self == nb::self,
nb::sig("def __eq__(self, arg: object, /) -> bool"));
device.def(nb::self != nb::self,
nb::sig("def __ne__(self, arg: object, /) -> bool"));
// Site class
auto site = nb::class_<fomac::Session::Device::Site>(
device, "Site",
"A site represents a potential qubit location on a quantum device.");
site.def("index", &fomac::Session::Device::Site::getIndex,
"Returns the index of the site.");
site.def("t1", &fomac::Session::Device::Site::getT1,
"Returns the T1 coherence time of the site.");
site.def("t2", &fomac::Session::Device::Site::getT2,
"Returns the T2 coherence time of the site.");
site.def("name", &fomac::Session::Device::Site::getName,
"Returns the name of the site.");
site.def("x_coordinate", &fomac::Session::Device::Site::getXCoordinate,
"Returns the x coordinate of the site.");
site.def("y_coordinate", &fomac::Session::Device::Site::getYCoordinate,
"Returns the y coordinate of the site.");
site.def("z_coordinate", &fomac::Session::Device::Site::getZCoordinate,
"Returns the z coordinate of the site.");
site.def("is_zone", &fomac::Session::Device::Site::isZone,
"Returns whether the site is a zone.");
site.def("x_extent", &fomac::Session::Device::Site::getXExtent,
"Returns the x extent of the site.");
site.def("y_extent", &fomac::Session::Device::Site::getYExtent,
"Returns the y extent of the site.");
site.def("z_extent", &fomac::Session::Device::Site::getZExtent,
"Returns the z extent of the site.");
site.def("module_index", &fomac::Session::Device::Site::getModuleIndex,
"Returns the index of the module the site belongs to.");
site.def("submodule_index", &fomac::Session::Device::Site::getSubmoduleIndex,
"Returns the index of the submodule the site belongs to.");
site.def("__repr__", [](const fomac::Session::Device::Site& s) {
return "<Site index=" + std::to_string(s.getIndex()) + ">";
});
site.def(nb::self == nb::self,
nb::sig("def __eq__(self, arg: object, /) -> bool"));
site.def(nb::self != nb::self,
nb::sig("def __ne__(self, arg: object, /) -> bool"));
// Operation class
auto operation = nb::class_<fomac::Session::Device::Operation>(
device, "Operation",
"An operation represents a quantum operation that can be performed on a "
"quantum device.");
operation.def("name", &fomac::Session::Device::Operation::getName,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the name of the operation.");
operation.def("qubits_num", &fomac::Session::Device::Operation::getQubitsNum,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the number of qubits the operation acts on.");
operation.def(
"parameters_num", &fomac::Session::Device::Operation::getParametersNum,
"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the number of parameters the operation has.");
operation.def("duration", &fomac::Session::Device::Operation::getDuration,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the duration of the operation.");
operation.def("fidelity", &fomac::Session::Device::Operation::getFidelity,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the fidelity of the operation.");
operation.def("interaction_radius",
&fomac::Session::Device::Operation::getInteractionRadius,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the interaction radius of the operation.");
operation.def(
"blocking_radius", &fomac::Session::Device::Operation::getBlockingRadius,
"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the blocking radius of the operation.");
operation.def(
"idling_fidelity", &fomac::Session::Device::Operation::getIdlingFidelity,
"sites"_a.sig("...") = std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the idling fidelity of the operation.");
operation.def("is_zoned", &fomac::Session::Device::Operation::isZoned,
"Returns whether the operation is zoned.");
operation.def("sites", &fomac::Session::Device::Operation::getSites,
"Returns the list of sites the operation can be performed on.");
operation.def("site_pairs", &fomac::Session::Device::Operation::getSitePairs,
"Returns the list of site pairs the local 2-qubit operation "
"can be performed on.");
operation.def("mean_shuttling_speed",
&fomac::Session::Device::Operation::getMeanShuttlingSpeed,
"sites"_a.sig("...") =
std::vector<fomac::Session::Device::Site>{},
"params"_a.sig("...") = std::vector<double>{},
"Returns the mean shuttling speed of the operation.");
operation.def("__repr__", [](const fomac::Session::Device::Operation& op) {
return "<Operation name=\"" + op.getName() + "\">";
});
operation.def(nb::self == nb::self,
nb::sig("def __eq__(self, arg: object, /) -> bool"));
operation.def(nb::self != nb::self,
nb::sig("def __ne__(self, arg: object, /) -> bool"));
// Module-level function to add dynamic device libraries
m.def(
"add_dynamic_device_library",
[](const std::string& libraryPath, const std::string& prefix,
const std::optional<std::string>& baseUrl = std::nullopt,
const std::optional<std::string>& token = std::nullopt,
const std::optional<std::string>& authFile = std::nullopt,
const std::optional<std::string>& authUrl = std::nullopt,
const std::optional<std::string>& username = std::nullopt,
const std::optional<std::string>& password = std::nullopt,
const std::optional<std::string>& custom1 = std::nullopt,
const std::optional<std::string>& custom2 = std::nullopt,
const std::optional<std::string>& custom3 = std::nullopt,
const std::optional<std::string>& custom4 = std::nullopt,
const std::optional<std::string>& custom5 =
std::nullopt) -> fomac::Session::Device {
const qdmi::DeviceSessionConfig config{.baseUrl = baseUrl,
.token = token,
.authFile = authFile,
.authUrl = authUrl,
.username = username,
.password = password,
.custom1 = custom1,
.custom2 = custom2,
.custom3 = custom3,
.custom4 = custom4,
.custom5 = custom5};
auto* const qdmiDevice = qdmi::Driver::get().addDynamicDeviceLibrary(
libraryPath, prefix, config);
return fomac::Session::Device::fromQDMIDevice(qdmiDevice);
},
"library_path"_a, "prefix"_a, nb::kw_only(), "base_url"_a = std::nullopt,
"token"_a = std::nullopt, "auth_file"_a = std::nullopt,
"auth_url"_a = std::nullopt, "username"_a = std::nullopt,
"password"_a = std::nullopt, "custom1"_a = std::nullopt,
"custom2"_a = std::nullopt, "custom3"_a = std::nullopt,
"custom4"_a = std::nullopt, "custom5"_a = std::nullopt,
R"pb(Load a dynamic device library into the QDMI driver.
This function loads a shared library (.so, .dll, or .dylib) that implements a QDMI device interface and makes it available for use in sessions.
Args:
library_path: Path to the shared library file to load.
prefix: Function prefix used by the library (e.g., "MY_DEVICE").
base_url: Optional base URL for the device API endpoint.
token: Optional authentication token.
auth_file: Optional path to authentication file.
auth_url: Optional authentication server URL.
username: Optional username for authentication.
password: Optional password for authentication.
custom1: Optional custom configuration parameter 1.
custom2: Optional custom configuration parameter 2.
custom3: Optional custom configuration parameter 3.
custom4: Optional custom configuration parameter 4.
custom5: Optional custom configuration parameter 5.
Returns:
Device: The newly loaded device that can be used to create backends.
Raises:
RuntimeError: If library loading fails or configuration is invalid.
Examples:
Load a device library with configuration:
>>> import mqt.core.fomac as fomac
>>> device = fomac.add_dynamic_device_library(
... "/path/to/libmy_device.so", "MY_DEVICE", base_url="http://localhost:8080", custom1="API_V2"
... )
Now the device can be used directly:
>>> from mqt.core.plugins.qiskit import QDMIBackend
>>> backend = QDMIBackend(device=device))pb");
}
} // namespace mqt