Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
074c7ff
:sparkles: QDMI authentication via FoMaC
marcelwa Dec 3, 2025
f1d4360
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 3, 2025
c184cc3
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 4, 2025
9d17fe3
:recycle: Don't re-expose session parameter enum
marcelwa Dec 4, 2025
97a863c
:recycle: Rename `setSessionParameter` to `setParameter`
marcelwa Dec 4, 2025
5705a51
:fire: Remove module-level convenience functions for parameter settin…
marcelwa Dec 4, 2025
b2f8833
:label: Propagate changes to `.pyi`
marcelwa Dec 4, 2025
4369473
:recycle: Session authentication via constructor parameters
marcelwa Dec 4, 2025
84e6f35
:recycle: Rename the `FoMaC` class to `Session`
marcelwa Dec 4, 2025
6a4dc71
:recycle: Adjust Qiskit-QDMI Python interface to adhere to new API
marcelwa Dec 4, 2025
8380a22
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 4, 2025
594b3b3
:white_check_mark: Add placeholder tests for authentication
marcelwa Dec 4, 2025
578b5f2
:bug: Guard session allocation
marcelwa Dec 4, 2025
b6ffb8a
:recycle: Improve URL validation regex
marcelwa Dec 4, 2025
1db21eb
:art: Address CodeRabbit's suggestions
marcelwa Dec 4, 2025
ed6d6b4
:memo: Update documentation to reflect code changes
marcelwa Dec 4, 2025
321ee04
:sparkles: Expose session authentication to QDMIProvider initializati…
marcelwa Dec 4, 2025
7f5cbe9
:bug: Fixed regex format
marcelwa Dec 4, 2025
36aaeae
:white_check_mark: Add authentication FoMaC C++ tests
marcelwa Dec 4, 2025
b4f495c
:rotating_light: Remove unused header
marcelwa Dec 4, 2025
25b13ab
:memo: Documentation on session authentication
marcelwa Dec 4, 2025
4dae4f1
:memo: CHANGELOG
marcelwa Dec 4, 2025
5655d59
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 4, 2025
bed169b
:art: Light code cleanup
marcelwa Dec 4, 2025
9b76cd3
Merge branch 'main' into qdmi-auth
marcelwa Dec 4, 2025
3206c7d
:sparkles: Expose CUSTOM `QDMI_Program_Format` parameters
marcelwa Dec 5, 2025
77ed885
:art: Cleanup Session constructor
marcelwa Dec 5, 2025
5ffabe0
Merge branch 'main' into qdmi-auth
marcelwa Dec 5, 2025
fe6b067
:art: Cleanup Session constructor in bindings
marcelwa Dec 5, 2025
8f1b299
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 5, 2025
7c8047a
:safety_vest: Ensure partially instantiated sessions get cleaned up p…
marcelwa Dec 5, 2025
5680e80
:art: Implement CodeRabbit's suggestions
marcelwa Dec 5, 2025
3d8d402
:recycle: Refactor URL validation to allow local URLs and IPs
marcelwa Dec 5, 2025
9843d31
:art: Refactor QDMI Provider args to kwargs
marcelwa Dec 5, 2025
f95d547
:recycle: Expose `QDMI_DEVICE_SESSION_PARAMETER`s via the `Driver`
marcelwa Dec 5, 2025
b0fed9a
:rotating_light: Address `clang-tidy` warnings
marcelwa Dec 6, 2025
69467b9
:recycle: Refactor `QDMI_Device_impl_d` and `Session` initialization …
marcelwa Dec 6, 2025
fbb7873
:white_check_mark: Stricter Session tests to properly test updated pa…
marcelwa Dec 6, 2025
74cfd1d
:white_check_mark: Test `Driver::addDynamicDeviceLibrary`
marcelwa Dec 6, 2025
7882499
:green_heart: Fix RTD build
marcelwa Dec 6, 2025
106452c
:art: Prefer SPDLOG macros over function calls
marcelwa Dec 6, 2025
d0d132c
:sparkles: Expose device library loading to Python
marcelwa Dec 6, 2025
2e10639
Merge branch 'main' into qdmi-auth
marcelwa Dec 6, 2025
f0b3a32
:art: Implement CodeRabbit's suggestions
marcelwa Dec 6, 2025
3fb8b1c
:rotating_light: Fix `clang-tidy` warnings
marcelwa Dec 6, 2025
ffb8ea5
Merge branch 'main' into qdmi-auth
marcelwa Dec 6, 2025
685c609
Merge branch 'main' into qdmi-auth
burgholzer Dec 6, 2025
5cd5f00
🩹 ensure session stays alive in provider
burgholzer Dec 6, 2025
0a4f68f
♻️ refactor provider initialization to use session kwargs
burgholzer Dec 6, 2025
8e7938c
🎨 remove redundant inline
burgholzer Dec 6, 2025
5ea53a6
✅♻️ refine smoke tests
burgholzer Dec 6, 2025
7b6fb8f
🐛 Fix custom QDMI property and parameter handling in SC and NA devices
burgholzer Dec 7, 2025
f8e719c
🐛 Lock the right mutex in the DD QDMI device
burgholzer Dec 7, 2025
6be3b68
🎨 remove redundant initialization
burgholzer Dec 7, 2025
5b7bd74
♻️ Enable thread-safe reference counting for QDMI devices singletons
burgholzer Dec 7, 2025
f9f0b6b
♻️ Allow repeated loading of QDMI device library with potentially dif…
burgholzer Dec 7, 2025
23b8846
🎨 slightly adjust session parameter setter
burgholzer Dec 7, 2025
951035b
🎨 reduce redundancy via new macro
burgholzer Dec 7, 2025
8e84370
♻️ slightly refactor reference counting
burgholzer Dec 7, 2025
d617428
🔥 remove openLibHandles
burgholzer Dec 7, 2025
d6a5467
✅ add one more test case
burgholzer Dec 7, 2025
e432e56
🚚 move `NA` QDMI device in its right place
burgholzer Dec 7, 2025
2e20fab
🩹 fix include dir
burgholzer Dec 7, 2025
80e88dc
📝 better singleton management docstrings
burgholzer Dec 7, 2025
086f7b2
🩹 fix invalid argument check
burgholzer Dec 7, 2025
0b74445
🚨 additional clang-tidy naming convention rule
burgholzer Dec 7, 2025
6d3dc52
♻️ rework thread-safe singleton logic
burgholzer Dec 7, 2025
7af7e00
Merge branch 'main' into qdmi-auth
burgholzer Dec 7, 2025
cb6f1c2
Revert "🚨 additional clang-tidy naming convention rule"
burgholzer Dec 7, 2025
676a8a1
♻️ simplify handling of static deinitialization order fiasco
burgholzer Dec 7, 2025
090ee48
🚨 clang-tidy
burgholzer Dec 7, 2025
724d2b8
🚨 fix compiler and linter warnings
burgholzer Dec 7, 2025
a3023d5
✨ add common definitions and utilities for QDMI
burgholzer Dec 7, 2025
59b6db4
:memo: Add missing PR reference
marcelwa Dec 7, 2025
1a49aea
:green_heart: Fix Windows tests by using `EXPECT_STREQ` instead of `E…
marcelwa Dec 7, 2025
df67ab4
:recycle: Refactor URL validation regex to allow IPv4 and IPv6 addresses
marcelwa Dec 7, 2025
2ea83b7
:pencil2: Fix typo
marcelwa Dec 7, 2025
931e0e4
:memo: Add comments to highlight the subtle difference between `strnc…
marcelwa Dec 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 101 additions & 74 deletions bindings/fomac/fomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,52 @@
using namespace py::literals;

PYBIND11_MODULE(MQT_CORE_MODULE_NAME, m, py::mod_gil_not_used()) {
auto session = py::class_<fomac::Session>(m, "Session");

const fomac::SessionConfig defaultConfig;
session.def(
py::init(
[](const std::optional<std::string>& token,

Check warning on line 34 in bindings/fomac/fomac.cpp

View workflow job for this annotation

GitHub Actions / 🇨‌ Lint / 🚨 Lint

bindings/fomac/fomac.cpp:34:25 [misc-include-cleaner]

no header providing "std::optional" is directly included
const std::optional<std::string>& authFile,
const std::optional<std::string>& authUrl,
const std::optional<std::string>& username,
const std::optional<std::string>& password,
const std::optional<std::string>& projectId) -> fomac::Session {
fomac::SessionConfig config;
config.token = token;
config.authFile = authFile;
config.authUrl = authUrl;
config.username = username;
config.password = password;
config.projectId = projectId;
return fomac::Session{config};
}),
"token"_a = defaultConfig.token, "auth_file"_a = defaultConfig.authFile,
"auth_url"_a = defaultConfig.authUrl,
"username"_a = defaultConfig.username,
"password"_a = defaultConfig.password,
"project_id"_a = defaultConfig.projectId);

session.def("get_devices", &fomac::Session::getDevices);

// Job class
auto job = py::class_<fomac::FoMaC::Job>(m, "Job");
job.def("check", &fomac::FoMaC::Job::check);
job.def("wait", &fomac::FoMaC::Job::wait, "timeout"_a = 0);
job.def("cancel", &fomac::FoMaC::Job::cancel);
job.def("get_shots", &fomac::FoMaC::Job::getShots);
job.def("get_counts", &fomac::FoMaC::Job::getCounts);
job.def("get_dense_statevector", &fomac::FoMaC::Job::getDenseStateVector);
job.def("get_dense_probabilities", &fomac::FoMaC::Job::getDenseProbabilities);
job.def("get_sparse_statevector", &fomac::FoMaC::Job::getSparseStateVector);
auto job = py::class_<fomac::Session::Job>(m, "Job");
job.def("check", &fomac::Session::Job::check);
job.def("wait", &fomac::Session::Job::wait, "timeout"_a = 0);
job.def("cancel", &fomac::Session::Job::cancel);
job.def("get_shots", &fomac::Session::Job::getShots);
job.def("get_counts", &fomac::Session::Job::getCounts);
job.def("get_dense_statevector", &fomac::Session::Job::getDenseStateVector);
job.def("get_dense_probabilities",
&fomac::Session::Job::getDenseProbabilities);
job.def("get_sparse_statevector", &fomac::Session::Job::getSparseStateVector);
job.def("get_sparse_probabilities",
&fomac::FoMaC::Job::getSparseProbabilities);
job.def_property_readonly("id", &fomac::FoMaC::Job::getId);
&fomac::Session::Job::getSparseProbabilities);
job.def_property_readonly("id", &fomac::Session::Job::getId);
job.def_property_readonly("program_format",
&fomac::FoMaC::Job::getProgramFormat);
job.def_property_readonly("program", &fomac::FoMaC::Job::getProgram);
job.def_property_readonly("num_shots", &fomac::FoMaC::Job::getNumShots);
&fomac::Session::Job::getProgramFormat);
job.def_property_readonly("program", &fomac::Session::Job::getProgram);
job.def_property_readonly("num_shots", &fomac::Session::Job::getNumShots);
job.def(py::self == py::self); // NOLINT(misc-redundant-expression)
job.def(py::self != py::self); // NOLINT(misc-redundant-expression)

Expand Down Expand Up @@ -79,7 +108,7 @@
.export_values()
.finalize();

auto device = py::class_<fomac::FoMaC::Device>(m, "Device");
auto device = py::class_<fomac::Session::Device>(m, "Device");

py::native_enum<QDMI_Device_Status>(device, "Status", "enum.Enum",
"Enumeration of device status.")
Expand All @@ -92,98 +121,96 @@
.export_values()
.finalize();

auto site = py::class_<fomac::FoMaC::Device::Site>(device, "Site");
site.def("index", &fomac::FoMaC::Device::Site::getIndex);
site.def("t1", &fomac::FoMaC::Device::Site::getT1);
site.def("t2", &fomac::FoMaC::Device::Site::getT2);
site.def("name", &fomac::FoMaC::Device::Site::getName);
site.def("x_coordinate", &fomac::FoMaC::Device::Site::getXCoordinate);
site.def("y_coordinate", &fomac::FoMaC::Device::Site::getYCoordinate);
site.def("z_coordinate", &fomac::FoMaC::Device::Site::getZCoordinate);
site.def("is_zone", &fomac::FoMaC::Device::Site::isZone);
site.def("x_extent", &fomac::FoMaC::Device::Site::getXExtent);
site.def("y_extent", &fomac::FoMaC::Device::Site::getYExtent);
site.def("z_extent", &fomac::FoMaC::Device::Site::getZExtent);
site.def("module_index", &fomac::FoMaC::Device::Site::getModuleIndex);
site.def("submodule_index", &fomac::FoMaC::Device::Site::getSubmoduleIndex);
site.def("__repr__", [](const fomac::FoMaC::Device::Site& s) {
auto site = py::class_<fomac::Session::Device::Site>(device, "Site");
site.def("index", &fomac::Session::Device::Site::getIndex);
site.def("t1", &fomac::Session::Device::Site::getT1);
site.def("t2", &fomac::Session::Device::Site::getT2);
site.def("name", &fomac::Session::Device::Site::getName);
site.def("x_coordinate", &fomac::Session::Device::Site::getXCoordinate);
site.def("y_coordinate", &fomac::Session::Device::Site::getYCoordinate);
site.def("z_coordinate", &fomac::Session::Device::Site::getZCoordinate);
site.def("is_zone", &fomac::Session::Device::Site::isZone);
site.def("x_extent", &fomac::Session::Device::Site::getXExtent);
site.def("y_extent", &fomac::Session::Device::Site::getYExtent);
site.def("z_extent", &fomac::Session::Device::Site::getZExtent);
site.def("module_index", &fomac::Session::Device::Site::getModuleIndex);
site.def("submodule_index", &fomac::Session::Device::Site::getSubmoduleIndex);
site.def("__repr__", [](const fomac::Session::Device::Site& s) {
return "<Site index=" + std::to_string(s.getIndex()) + ">";
});
site.def(py::self == py::self); // NOLINT(misc-redundant-expression)
site.def(py::self != py::self); // NOLINT(misc-redundant-expression)

auto operation =
py::class_<fomac::FoMaC::Device::Operation>(device, "Operation");
operation.def("name", &fomac::FoMaC::Device::Operation::getName,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
py::class_<fomac::Session::Device::Operation>(device, "Operation");
operation.def("name", &fomac::Session::Device::Operation::getName,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("qubits_num", &fomac::FoMaC::Device::Operation::getQubitsNum,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
operation.def("qubits_num", &fomac::Session::Device::Operation::getQubitsNum,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("parameters_num",
&fomac::FoMaC::Device::Operation::getParametersNum,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
&fomac::Session::Device::Operation::getParametersNum,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("duration", &fomac::FoMaC::Device::Operation::getDuration,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
operation.def("duration", &fomac::Session::Device::Operation::getDuration,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("fidelity", &fomac::FoMaC::Device::Operation::getFidelity,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
operation.def("fidelity", &fomac::Session::Device::Operation::getFidelity,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("interaction_radius",
&fomac::FoMaC::Device::Operation::getInteractionRadius,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
&fomac::Session::Device::Operation::getInteractionRadius,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("blocking_radius",
&fomac::FoMaC::Device::Operation::getBlockingRadius,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
&fomac::Session::Device::Operation::getBlockingRadius,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("idling_fidelity",
&fomac::FoMaC::Device::Operation::getIdlingFidelity,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
&fomac::Session::Device::Operation::getIdlingFidelity,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("is_zoned", &fomac::FoMaC::Device::Operation::isZoned);
operation.def("sites", &fomac::FoMaC::Device::Operation::getSites);
operation.def("site_pairs", &fomac::FoMaC::Device::Operation::getSitePairs);
operation.def("is_zoned", &fomac::Session::Device::Operation::isZoned);
operation.def("sites", &fomac::Session::Device::Operation::getSites);
operation.def("site_pairs", &fomac::Session::Device::Operation::getSitePairs);
operation.def("mean_shuttling_speed",
&fomac::FoMaC::Device::Operation::getMeanShuttlingSpeed,
"sites"_a = std::vector<fomac::FoMaC::Device::Site>{},
&fomac::Session::Device::Operation::getMeanShuttlingSpeed,
"sites"_a = std::vector<fomac::Session::Device::Site>{},
"params"_a = std::vector<double>{});
operation.def("__repr__", [](const fomac::FoMaC::Device::Operation& op) {
operation.def("__repr__", [](const fomac::Session::Device::Operation& op) {
return "<Operation name=\"" + op.getName() + "\">";
});
operation.def(py::self == py::self); // NOLINT(misc-redundant-expression)
operation.def(py::self != py::self); // NOLINT(misc-redundant-expression)

device.def("name", &fomac::FoMaC::Device::getName);
device.def("version", &fomac::FoMaC::Device::getVersion);
device.def("status", &fomac::FoMaC::Device::getStatus);
device.def("library_version", &fomac::FoMaC::Device::getLibraryVersion);
device.def("qubits_num", &fomac::FoMaC::Device::getQubitsNum);
device.def("sites", &fomac::FoMaC::Device::getSites);
device.def("regular_sites", &fomac::FoMaC::Device::getRegularSites);
device.def("zones", &fomac::FoMaC::Device::getZones);
device.def("operations", &fomac::FoMaC::Device::getOperations);
device.def("coupling_map", &fomac::FoMaC::Device::getCouplingMap);
device.def("needs_calibration", &fomac::FoMaC::Device::getNeedsCalibration);
device.def("length_unit", &fomac::FoMaC::Device::getLengthUnit);
device.def("name", &fomac::Session::Device::getName);
device.def("version", &fomac::Session::Device::getVersion);
device.def("status", &fomac::Session::Device::getStatus);
device.def("library_version", &fomac::Session::Device::getLibraryVersion);
device.def("qubits_num", &fomac::Session::Device::getQubitsNum);
device.def("sites", &fomac::Session::Device::getSites);
device.def("regular_sites", &fomac::Session::Device::getRegularSites);
device.def("zones", &fomac::Session::Device::getZones);
device.def("operations", &fomac::Session::Device::getOperations);
device.def("coupling_map", &fomac::Session::Device::getCouplingMap);
device.def("needs_calibration", &fomac::Session::Device::getNeedsCalibration);
device.def("length_unit", &fomac::Session::Device::getLengthUnit);
device.def("length_scale_factor",
&fomac::FoMaC::Device::getLengthScaleFactor);
device.def("duration_unit", &fomac::FoMaC::Device::getDurationUnit);
&fomac::Session::Device::getLengthScaleFactor);
device.def("duration_unit", &fomac::Session::Device::getDurationUnit);
device.def("duration_scale_factor",
&fomac::FoMaC::Device::getDurationScaleFactor);
device.def("min_atom_distance", &fomac::FoMaC::Device::getMinAtomDistance);
&fomac::Session::Device::getDurationScaleFactor);
device.def("min_atom_distance", &fomac::Session::Device::getMinAtomDistance);
device.def("supported_program_formats",
&fomac::FoMaC::Device::getSupportedProgramFormats);
device.def("submit_job", &fomac::FoMaC::Device::submitJob, "program"_a,
&fomac::Session::Device::getSupportedProgramFormats);
device.def("submit_job", &fomac::Session::Device::submitJob, "program"_a,
"program_format"_a, "num_shots"_a);
device.def("__repr__", [](const fomac::FoMaC::Device& dev) {
device.def("__repr__", [](const fomac::Session::Device& dev) {
return "<Device name=\"" + dev.getName() + "\">";
});
device.def(py::self == py::self); // NOLINT(misc-redundant-expression)
device.def(py::self != py::self); // NOLINT(misc-redundant-expression)

m.def("devices", &fomac::FoMaC::getDevices);
}

} // namespace mqt
14 changes: 7 additions & 7 deletions bindings/na/fomac/fomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ PYBIND11_MODULE(MQT_CORE_MODULE_NAME, m, py::mod_gil_not_used()) {
pybind11::module_::import("mqt.core.fomac");

auto device =
py::class_<na::FoMaC::Device, fomac::FoMaC::Device>(m, "Device");
py::class_<na::Session::Device, fomac::Session::Device>(m, "Device");

auto lattice = py::class_<na::Device::Lattice>(device, "Lattice");

Expand Down Expand Up @@ -91,22 +91,22 @@ PYBIND11_MODULE(MQT_CORE_MODULE_NAME, m, py::mod_gil_not_used()) {
lattice.def(py::self == py::self);
lattice.def(py::self != py::self);

device.def_property_readonly("traps", &na::FoMaC::Device::getTraps);
device.def_property_readonly("t1", [](const na::FoMaC::Device& dev) {
device.def_property_readonly("traps", &na::Session::Device::getTraps);
device.def_property_readonly("t1", [](const na::Session::Device& dev) {
return dev.getDecoherenceTimes().t1;
});
device.def_property_readonly("t2", [](const na::FoMaC::Device& dev) {
device.def_property_readonly("t2", [](const na::Session::Device& dev) {
return dev.getDecoherenceTimes().t2;
});
device.def("__repr__", [](const fomac::FoMaC::Device& dev) {
device.def("__repr__", [](const fomac::Session::Device& dev) {
return "<Device name=\"" + dev.getName() + "\">";
});
device.def(py::self == py::self);
device.def(py::self != py::self);

m.def("devices", &na::FoMaC::getDevices);
m.def("devices", &na::Session::getDevices);
device.def_static("try_create_from_device",
&na::FoMaC::Device::tryCreateFromDevice, "device"_a);
&na::Session::Device::tryCreateFromDevice, "device"_a);
}
// NOLINTEND(misc-redundant-expression)
} // namespace mqt
Loading
Loading