-
-
Notifications
You must be signed in to change notification settings - Fork 73
β¨ Add an optional packaged QDMI Driver extension #2230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Optional packaged QDMI driver extension | ||
|
|
||
| Status: independently rebased and validated locally. | ||
|
|
||
| ## Motivation and settled boundary | ||
|
|
||
| Installed providers need catalogue discovery and targeted stable-ID opening | ||
| without importing vendor Python code or copying libraries beside the driver. | ||
| Core's packaged driver provides an optional private extension for this purpose. | ||
| The standard Client ABI remains usable with drivers that lack that extension. | ||
| Standardizing discovery/configuration is QDMI v2 work. | ||
|
|
||
| This is Core #2230 on #2229, targeting Core 4.1 / QDMI 1.4. It does not depend | ||
| on metadata removal, batching, payload capabilities, or compiler changes. | ||
|
|
||
| ## Implementation | ||
|
|
||
| - Load the two optional private symbols in the Client wrapper. Staging a | ||
| manifest does not select the process-wide driver; successful raw targeted | ||
| allocation does, even when subsequent initialization fails. | ||
| - Stage trusted manifests transactionally at lowest precedence, freeze the | ||
| registry after successful construction, and keep canonical paths idempotent. | ||
| - Open exactly one stable ID with strict per-call overrides. Preserve sized | ||
| custom values, reject malformed paths/IDs, and propagate provider errors. | ||
| - Discover Python manifests using entry-point metadata and wheel RECORD paths, | ||
| never provider imports. Invalid automatic entries warn and are skipped; | ||
| explicit staging remains strict. | ||
| - Retain initialized provider libraries across independent sessions. Complete | ||
| initialization before moving the session owner, including on Windows. | ||
|
|
||
| The entry points are qdmi::default_driver::addManifest/openDevice and the Python | ||
| default_driver submodule. No public QDMI C header changes are needed. | ||
| Installed-consumer packaging is the separate follow-up #2231. | ||
|
|
||
| ## Acceptance | ||
|
|
||
| Run the independent release build and CTest suite, generated stubs, QDMI/SDK | ||
| Python tests, repository lint, and C++ lint. Check absent optional symbols, | ||
| selection timing, freeze rollback, idempotent paths, strict overrides, valid | ||
| warning outputs, malformed JSON, UTF-8 paths, and session lifetime. Discovery | ||
| tests must reject missing RECORD, ambiguous/off-anchor paths and traversal while | ||
| proving that provider code is not imported. Retain current optional-device | ||
| configurations, concurrency, and compiler rules. | ||
|
|
||
| The release suite passed 3,873 tests with one existing skip. All 467 selected | ||
| Python tests passed. Stub generation, repository lint and C++ lint passed. | ||
|
|
||
| ## Recovery and non-goals | ||
|
|
||
| Keep useful commits, human attribution and review threads. Use guarded pushes; | ||
| do not create archive branches or request reviews. There is no new registry API, | ||
| public discovery standard, scheduler policy, or payload contract here. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,45 @@ different Driver fails. A failed load, ABI check, symbol check, or raw-session | |
| allocation does not select a Driver, so a later call can retry. MQT Core keeps | ||
| the selected shared library loaded while its function pointers can be used. | ||
|
|
||
| ## Optional Packaged-Driver Extension | ||
|
|
||
| MQT Core's packaged Driver adds two private symbols to the same shared library | ||
| that exports the standard Client interface: | ||
|
|
||
| - `MQT_CORE_QDMI_driver_add_manifest_v1` stages a trusted package manifest. | ||
| - `MQT_CORE_QDMI_driver_session_alloc_for_device_v1` allocates a session for one | ||
| configured stable ID. | ||
|
|
||
| These symbols are an MQT Core extension. They are not part of a public QDMI | ||
| header, and another Client driver can omit them. MQT Core resolves them as | ||
| optional symbols and calls them only through the extension API. Missing | ||
| extension symbols do not prevent standard Client sessions. Generic | ||
| {cpp-api:func}`qdmi::Session::openDevice` and Python | ||
| {py:func}`mqt.core.qdmi.open_device` enumerate the standard Client device list | ||
| and never use the private targeted-session symbol. | ||
|
|
||
| Use {cpp-api:func}`qdmi::default_driver::addManifest` or Python | ||
| {py:func}`mqt.core.qdmi.default_driver.add_manifest` before the packaged Driver | ||
| freezes its registry. Staging the packaged library does not select it as the | ||
| generic Client driver. The first successful raw standard or targeted session | ||
| allocation selects a Client driver. A later targeted-session initialization or | ||
| device query failure does not undo that selection. | ||
|
Comment on lines
+58
to
+61
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that some of this will (have to) change based on the review in the PR this is stacked on. |
||
|
|
||
| By default, the `default_driver` extension resolves MQT Core's packaged Driver | ||
| and ignores `MQT_CORE_QDMI_DRIVER`. An explicit `driver_path` overrides that | ||
| default for a compatible extension. The process selection rule still prevents | ||
| switching Drivers after a successful raw allocation. Standard Client sessions | ||
| use the selection order above, including the environment override. | ||
|
|
||
| Use {cpp-api:func}`qdmi::default_driver::openDevice` or Python | ||
| {py:func}`mqt.core.qdmi.default_driver.open_device` when an application | ||
| deliberately depends on the packaged Driver. The targeted call merges manifest | ||
| defaults with the supplied JSON or Python overrides. It rejects unsupported | ||
| parameters and malformed configuration, propagates device-library status codes, | ||
| and requires the session to expose exactly one device. Each call creates an | ||
| independent session. The returned device and its derived wrappers retain that | ||
| session until the last wrapper is destroyed. | ||
|
|
||
| ## Building the Bundled Devices | ||
|
|
||
| Standalone MQT Core builds include the DDSIM and superconducting QDMI device | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -494,6 +494,20 @@ class Site; | |
| class Device; | ||
| class Operation; | ||
|
|
||
| namespace default_driver { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is "default_driver" really what we want to use in terms of nomenclature? |
||
| /// Stage one package manifest in MQT Core's optional driver extension. | ||
| void addManifest(const std::filesystem::path& path); | ||
|
|
||
| /// Open one default-driver device with strict merged session configuration. | ||
| /// @param id Stable device ID. | ||
| /// @param deviceSessionJson JSON session overrides. | ||
| /// @param driverPath Optional compatible extension path. By default, this call | ||
| /// uses MQT Core's packaged Driver and ignores `MQT_CORE_QDMI_DRIVER`. | ||
| [[nodiscard]] Device openDevice( | ||
| std::string_view id, std::string_view deviceSessionJson = {}, | ||
| const std::optional<std::filesystem::path>& driverPath = std::nullopt); | ||
| } // namespace default_driver | ||
|
|
||
| /** | ||
| * @brief Class representing the Session library. | ||
| * @details This class provides methods to query available devices and | ||
|
|
@@ -804,6 +818,10 @@ class Device { | |
| Device(QDMI_Device device, std::shared_ptr<detail::ClientSession> session) | ||
| : device_(device), session_(std::move(session)) {} | ||
|
|
||
| friend Device | ||
| default_driver::openDevice(std::string_view, std::string_view, | ||
| const std::optional<std::filesystem::path>&); | ||
|
|
||
| /// Wrap operation handles while retaining their owning device session. | ||
| [[nodiscard]] std::vector<Operation> | ||
| wrapOperations(std::span<const QDMI_Operation> operations) const; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wording here and throughout will have to be adapted based on the feedback on nomenclature in the lower PRs.