From 008170e512486f5367d1276cb04274e836dd71a2 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 13:21:19 +0200 Subject: [PATCH 01/13] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20opening?= =?UTF-8?q?=20existing=20QDMI=20jobs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- include/mqt-core/fomac/FoMaC.hpp | 10 ++++++ include/mqt-core/qdmi/driver/Driver.hpp | 9 +++++ src/fomac/FoMaC.cpp | 8 +++++ src/qdmi/driver/Driver.cpp | 35 ++++++++++++++++++ test/qdmi/driver/session_device.cpp | 19 +++++++++- test/qdmi/driver/test_driver.cpp | 48 +++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 1 deletion(-) diff --git a/include/mqt-core/fomac/FoMaC.hpp b/include/mqt-core/fomac/FoMaC.hpp index 652fffca3e..f275d6b0a0 100644 --- a/include/mqt-core/fomac/FoMaC.hpp +++ b/include/mqt-core/fomac/FoMaC.hpp @@ -551,6 +551,16 @@ class Device { const std::optional& custom4 = std::nullopt, const std::optional& custom5 = std::nullopt) const; + /** + * @brief Opens an existing job by its device-provided ID. + * @details Opening a job does not submit, clone, or modify the remote job. + * The returned handle can be used to query its state and retrieve results. + * @param jobId The nonempty opaque ID returned by @ref Job::getId. + * @throws std::runtime_error If the driver or device cannot open the job. + * @see QDMI_device_open_job + */ + [[nodiscard]] Job openJob(std::string_view jobId) const; + auto operator<=>(const Device&) const noexcept = default; private: diff --git a/include/mqt-core/qdmi/driver/Driver.hpp b/include/mqt-core/qdmi/driver/Driver.hpp index 974c754fd9..48b86ce4b0 100644 --- a/include/mqt-core/qdmi/driver/Driver.hpp +++ b/include/mqt-core/qdmi/driver/Driver.hpp @@ -123,6 +123,9 @@ struct DeviceLibrary { /// Function pointer to @ref QDMI_device_session_create_device_job. decltype(QDMI_device_session_create_device_job)* device_session_create_device_job{}; + /// Optional function pointer to @ref QDMI_device_session_open_device_job. + decltype(QDMI_device_session_open_device_job)* + device_session_open_device_job{}; /// Function pointer to @ref QDMI_device_job_free. decltype(QDMI_device_job_free)* device_job_free{}; /// Function pointer to @ref QDMI_device_job_set_parameter. @@ -269,6 +272,12 @@ struct QDMI_Device_impl_d { */ auto createJob(QDMI_Job* job) -> int; + /** + * @brief Opens an existing job for the device. + * @see QDMI_device_open_job + */ + auto openJob(const char* jobId, QDMI_Job* job) -> int; + /** * @brief Frees the job associated with the device. * @see QDMI_job_free diff --git a/src/fomac/FoMaC.cpp b/src/fomac/FoMaC.cpp index fb3e7156a6..dee784c54f 100644 --- a/src/fomac/FoMaC.cpp +++ b/src/fomac/FoMaC.cpp @@ -407,6 +407,14 @@ Job Device::submitJob(const std::span program, return jobWrapper; } +Job Device::openJob(const std::string_view jobId) const { + const std::string id{jobId}; + QDMI_Job job = nullptr; + qdmi::throwIfError(QDMI_device_open_job(device_.get(), id.c_str(), &job), + "Opening job"); + return Job{job, device_}; +} + void Device::setCustomJobParam(QDMI_Job job, const QDMI_Job_Parameter param, const CustomJobParameter& value) { std::visit( diff --git a/src/qdmi/driver/Driver.cpp b/src/qdmi/driver/Driver.cpp index 0e7be02538..d272f18684 100644 --- a/src/qdmi/driver/Driver.cpp +++ b/src/qdmi/driver/Driver.cpp @@ -122,6 +122,12 @@ DynamicDeviceLibrary::DynamicDeviceLibrary(const std::string& libName, throw std::runtime_error("Failed to load symbol: " + symbolName); \ } \ } +#define LOAD_OPTIONAL_DYNAMIC_SYMBOL(symbol) \ + { \ + const std::string symbolName = std::string(prefix) + "_QDMI_" + #symbol; \ + (symbol) = reinterpret_cast( \ + DL_SYM(libHandle_, symbolName.c_str())); \ + } //===----------------------------------------------------------------------===// try { @@ -136,6 +142,7 @@ DynamicDeviceLibrary::DynamicDeviceLibrary(const std::string& libName, LOAD_DYNAMIC_SYMBOL(device_session_set_parameter) // device job interface LOAD_DYNAMIC_SYMBOL(device_session_create_device_job) + LOAD_OPTIONAL_DYNAMIC_SYMBOL(device_session_open_device_job) LOAD_DYNAMIC_SYMBOL(device_job_free) LOAD_DYNAMIC_SYMBOL(device_job_set_parameter) LOAD_DYNAMIC_SYMBOL(device_job_query_property) @@ -234,6 +241,7 @@ void applyOverride(std::optional& value, #undef DL_OPEN #undef DL_SYM #undef DL_CLOSE +#undef LOAD_OPTIONAL_DYNAMIC_SYMBOL } // namespace qdmi QDMI_Device_impl_d::QDMI_Device_impl_d( @@ -397,6 +405,26 @@ auto QDMI_Device_impl_d::createJob(QDMI_Job* job) -> int { return QDMI_SUCCESS; } +auto QDMI_Device_impl_d::openJob(const char* const jobId, QDMI_Job* job) + -> int { + if (jobId == nullptr || jobId[0] == '\0' || job == nullptr) { + return QDMI_ERROR_INVALIDARGUMENT; + } + if (library_->device_session_open_device_job == nullptr) { + return QDMI_ERROR_NOTSUPPORTED; + } + QDMI_Device_Job deviceJob = nullptr; + const auto result = library_->device_session_open_device_job( + deviceSession_, jobId, &deviceJob); + if (result != QDMI_SUCCESS) { + return result; + } + auto uniqueJob = std::make_unique(deviceJob, this); + const auto it = jobs_.emplace(uniqueJob.get(), std::move(uniqueJob)).first; + *job = it->first; + return QDMI_SUCCESS; +} + auto QDMI_Device_impl_d::freeJob(QDMI_Job job) -> void { if (job != nullptr) { jobs_.erase(job); @@ -798,6 +826,13 @@ int QDMI_device_create_job(QDMI_Device dev, QDMI_Job* job) { return dev->createJob(job); } +int QDMI_device_open_job(QDMI_Device dev, const char* jobId, QDMI_Job* job) { + if (dev == nullptr) { + return QDMI_ERROR_INVALIDARGUMENT; + } + return dev->openJob(jobId, job); +} + void QDMI_job_free(QDMI_Job job) { if (job != nullptr) { job->free(); diff --git a/test/qdmi/driver/session_device.cpp b/test/qdmi/driver/session_device.cpp index 5f91e81268..5cfdd120fc 100644 --- a/test/qdmi/driver/session_device.cpp +++ b/test/qdmi/driver/session_device.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include struct QDMI_Child_Device_impl_d {}; @@ -27,6 +28,7 @@ struct QDMI_Device_Session_impl_d { struct QDMI_Device_Job_impl_d { QDMI_Device_Session session = nullptr; + std::string id = "session-job"; }; namespace { @@ -209,6 +211,21 @@ TEST_SESSION_QDMI_device_session_create_device_job(QDMI_Device_Session session, return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; } +extern "C" int TEST_SESSION_QDMI_device_session_open_device_job( + QDMI_Device_Session session, const char* jobId, QDMI_Device_Job* job) { + if (session == nullptr || !session->initialized || jobId == nullptr || + jobId[0] == '\0' || job == nullptr) { + return QDMI_ERROR_INVALIDARGUMENT; + } + if (std::string_view{jobId} != "session-job") { + return QDMI_ERROR_NOTFOUND; + } + // The QDMI C API transfers this allocation through an opaque raw handle. + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + *job = new (std::nothrow) QDMI_Device_Job_impl_d{session}; + return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; +} + extern "C" int TEST_SESSION_QDMI_device_job_set_parameter( QDMI_Device_Job job, QDMI_Device_Job_Parameter /*parameter*/, size_t /*size*/, const void* /*value*/) { @@ -222,7 +239,7 @@ extern "C" int TEST_SESSION_QDMI_device_job_query_property( prop != QDMI_DEVICE_JOB_PROPERTY_ID) { return QDMI_ERROR_INVALIDARGUMENT; } - return queryString("session-job", size, value, sizeRet); + return queryString(job->id, size, value, sizeRet); } extern "C" int TEST_SESSION_QDMI_device_job_submit(QDMI_Device_Job job) { diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 3b982cb172..11518bab28 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -455,6 +455,54 @@ TEST_P(DriverTest, JobCreate) { QDMI_ERROR_INVALIDARGUMENT); } +TEST_P(DriverTest, JobOpen) { + QDMI_Job job = nullptr; + const auto result = QDMI_device_open_job(device, "session-job", &job); + if (result == QDMI_ERROR_NOTSUPPORTED) { + return; + } + ASSERT_EQ(result, QDMI_SUCCESS); + ASSERT_NE(job, nullptr); + QDMI_job_free(job); + EXPECT_EQ(QDMI_device_open_job(device, "", &job), QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_device_open_job(device, "unknown", &job), QDMI_ERROR_NOTFOUND); +} + +TEST(JobOpenTest, OpensExistingJobThroughClientApi) { + const auto device = + openTestDevice(MQT_CORE_QDMI_SESSION_DEVICE, "TEST_SESSION"); + QDMI_Job job = nullptr; + ASSERT_EQ(QDMI_device_open_job(device, "session-job", &job), QDMI_SUCCESS); + ASSERT_NE(job, nullptr); + + size_t size = 0; + ASSERT_EQ( + QDMI_job_query_property(job, QDMI_JOB_PROPERTY_ID, 0, nullptr, &size), + QDMI_SUCCESS); + std::string id(size - 1, '\0'); + EXPECT_EQ(QDMI_job_query_property(job, QDMI_JOB_PROPERTY_ID, size, id.data(), + nullptr), + QDMI_SUCCESS); + EXPECT_EQ(id, "session-job"); + QDMI_job_free(job); + + EXPECT_EQ(QDMI_device_open_job(nullptr, "session-job", &job), + QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_device_open_job(device, nullptr, &job), + QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_device_open_job(device, "", &job), QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_device_open_job(device, "session-job", nullptr), + QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_device_open_job(device, "unknown", &job), QDMI_ERROR_NOTFOUND); +} + +TEST(FoMaCJobTest, OpensExistingJobs) { + const auto device = fomac::Session::createSessionlessDevice( + openTestDevice(MQT_CORE_QDMI_SESSION_DEVICE, "TEST_SESSION")); + const auto job = device.openJob("session-job"); + EXPECT_EQ(job.getId(), "session-job"); +} + TEST_P(DriverTest, JobSetParameter) { EXPECT_EQ(QDMI_job_set_parameter(nullptr, QDMI_JOB_PARAMETER_MAX, 0, nullptr), QDMI_ERROR_INVALIDARGUMENT); From b3421e66b67b83510e4fc1c81c94bbd00eabe9a0 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 13:37:13 +0200 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=90=8D=20Expose=20job=20reopening?= =?UTF-8?q?=20to=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- bindings/fomac/fomac.cpp | 8 ++++++++ python/mqt/core/fomac.pyi | 3 +++ test/python/fomac/test_fomac.py | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/bindings/fomac/fomac.cpp b/bindings/fomac/fomac.cpp index bad0b9681c..d2e7330e62 100644 --- a/bindings/fomac/fomac.cpp +++ b/bindings/fomac/fomac.cpp @@ -470,6 +470,14 @@ when the custom slot is unsupported.)pb"); "custom5"_a = nb::none(), nb::rv_policy::reference_internal, "Submits an exact byte payload to the device."); + device.def( + "open_job", + [](const fomac::Device& self, const std::string& jobId) { + return self.openJob(jobId); + }, + "job_id"_a, nb::rv_policy::reference_internal, + "Opens an existing job by its device-provided ID."); + device.def("__repr__", [](const fomac::Device& dev) { return ""; }); diff --git a/python/mqt/core/fomac.pyi b/python/mqt/core/fomac.pyi index b240309e9c..8b2b3e26e9 100644 --- a/python/mqt/core/fomac.pyi +++ b/python/mqt/core/fomac.pyi @@ -369,6 +369,9 @@ class Device: ) -> Job: """Submits an exact byte payload to the device.""" + def open_job(self, job_id: str) -> Job: + """Opens an existing job by its device-provided ID.""" + def __eq__(self, arg: object, /) -> bool: ... def __ne__(self, arg: object, /) -> bool: ... diff --git a/test/python/fomac/test_fomac.py b/test/python/fomac/test_fomac.py index 631c3ab4c2..4dd49cb73b 100644 --- a/test/python/fomac/test_fomac.py +++ b/test/python/fomac/test_fomac.py @@ -586,6 +586,12 @@ def test_device_submit_job_preserves_num_shots(ddsim_device: Device) -> None: assert job3.num_shots == 1000 +def test_device_open_job_reports_unsupported_provider(ddsim_device: Device) -> None: + """Expose job reopening through Python without requiring DDSIM support.""" + with pytest.raises(RuntimeError, match=r"Opening job: Not supported\."): + ddsim_device.open_job("unknown") + + @pytest.fixture def submitted_job(ddsim_device: Device) -> Job: """Fixture that provides a submitted job for testing. From 3cb178e87e8e63cac4ba02a14318722160730afa Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 13:48:51 +0200 Subject: [PATCH 03/13] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Stack=20job=20reopen?= =?UTF-8?q?ing=20on=20QDMI=201.3.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index c7f695d2b0..d2c48cdcfa 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -89,11 +89,11 @@ if(BUILD_MQT_CORE_TESTS) endif() # cmake-format: off -set(QDMI_MINIMUM_VERSION 1.3.2 +set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") -set(QDMI_VERSION 1.3.2 +set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "d05a0b418f42e54e9585d2e00af8ce23e745fd83" # v1.3.2 +set(QDMI_REV "ade7817b9bad239dcd9c25205f02d18977fd29b8" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") @@ -125,7 +125,7 @@ if(NOT TARGET spdlog::spdlog) cmake_dependent_option(SPDLOG_BUILD_SHARED "Build spdlog as shared library" ON "BUILD_MQT_CORE_SHARED_LIBS" OFF) FetchContent_Declare(spdlog URL ${SPDLOG_URL} FIND_PACKAGE_ARGS ${SPDLOG_VERSION}) - list(APPEND FETCH_PACKAGES spdlog) + list(PREPEND FETCH_PACKAGES spdlog) set(MQT_CORE_MANAGES_SPDLOG ON) endif() From fae511e287e4d5ab2da9677a548a44b3b8fa1437 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 13:54:37 +0200 Subject: [PATCH 04/13] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Refresh=20stacked=20?= =?UTF-8?q?QDMI=20revision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index d2c48cdcfa..8af47208d1 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "ade7817b9bad239dcd9c25205f02d18977fd29b8" # QDMI PR #485 +set(QDMI_REV "5657666975f0b13e1244da88ba800d320ba64b5e" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") From 400cb7b12d176ca2c097ff279a910d526de4cf1c Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 13:59:46 +0200 Subject: [PATCH 05/13] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Refresh=20QDMI=20CI?= =?UTF-8?q?=20fix=20revision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index 8af47208d1..384b1f5b07 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "5657666975f0b13e1244da88ba800d320ba64b5e" # QDMI PR #485 +set(QDMI_REV "c4ca15197e68a4b9783027c26ee94ffe0e74037f" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") From 0c08e30b15e53ff964bb9609668ddef53c083363 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 14:01:41 +0200 Subject: [PATCH 06/13] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Refresh=20QDMI=20con?= =?UTF-8?q?formance=20revision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index 384b1f5b07..519f091923 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "c4ca15197e68a4b9783027c26ee94ffe0e74037f" # QDMI PR #485 +set(QDMI_REV "04b48c1d651c5a9c0e492988c4b74a5e842778d6" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") From 949047e54ceadcaa13153a67f43b67c367b4c36c Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 14:06:11 +0200 Subject: [PATCH 07/13] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Refresh=20final=20QD?= =?UTF-8?q?MI=20lint=20revision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index 519f091923..986089d3fc 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "04b48c1d651c5a9c0e492988c4b74a5e842778d6" # QDMI PR #485 +set(QDMI_REV "0fd884b0afdd55883535f955822617aaa46bb0d2" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") From 0499d046d8896f5fee284dc4fc60badf7543ab8b Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 14:11:59 +0200 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=93=9D=20Add=20job=20reopening=20ch?= =?UTF-8?q?angelog=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 061cddfd4d..4260d9eac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ releases may include breaking changes. ### Added - 🐍 Start building CPython 3.15 wheels ([#2011]) ([**@denialhaag**]) +- ✨ Add support for retrieving existing QDMI jobs by ID in C++, Python, and the QDMI + driver ([#2008]) ([**@burgholzer**]) - ✨ Add PennyLane support for gate-based QDMI devices ([#2005]) ([**@burgholzer**]) - ✨ Integrate QDMI devices as MLIR compiler targets across C++, Python, and @@ -721,7 +723,11 @@ for previous changelogs._ +<<<<<<< HEAD [#2011]: https://github.com/munich-quantum-toolkit/core/pull/2011 +======= +[#2008]: https://github.com/munich-quantum-toolkit/core/pull/2008 +>>>>>>> f7fcb791d (📝 Add job reopening changelog entry) [#2007]: https://github.com/munich-quantum-toolkit/core/pull/2007 [#2006]: https://github.com/munich-quantum-toolkit/core/pull/2006 [#2005]: https://github.com/munich-quantum-toolkit/core/pull/2005 From 53850ce92a2e7fb5df24de94c919365336164a15 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 14:20:33 +0200 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=8E=A8=20Address=20QDMI=20driver=20?= =?UTF-8?q?lint=20findings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- src/qdmi/driver/Driver.cpp | 2 +- test/qdmi/driver/session_device.cpp | 6 +++--- test/qdmi/driver/test_driver.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qdmi/driver/Driver.cpp b/src/qdmi/driver/Driver.cpp index d272f18684..fa8fc32322 100644 --- a/src/qdmi/driver/Driver.cpp +++ b/src/qdmi/driver/Driver.cpp @@ -407,7 +407,7 @@ auto QDMI_Device_impl_d::createJob(QDMI_Job* job) -> int { auto QDMI_Device_impl_d::openJob(const char* const jobId, QDMI_Job* job) -> int { - if (jobId == nullptr || jobId[0] == '\0' || job == nullptr) { + if (jobId == nullptr || *jobId == '\0' || job == nullptr) { return QDMI_ERROR_INVALIDARGUMENT; } if (library_->device_session_open_device_job == nullptr) { diff --git a/test/qdmi/driver/session_device.cpp b/test/qdmi/driver/session_device.cpp index 5cfdd120fc..54a6e0fdad 100644 --- a/test/qdmi/driver/session_device.cpp +++ b/test/qdmi/driver/session_device.cpp @@ -207,14 +207,14 @@ TEST_SESSION_QDMI_device_session_create_device_job(QDMI_Device_Session session, } // The QDMI C API transfers this allocation through an opaque raw handle. // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - *job = new (std::nothrow) QDMI_Device_Job_impl_d{session}; + *job = new (std::nothrow) QDMI_Device_Job_impl_d{.session = session}; return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; } extern "C" int TEST_SESSION_QDMI_device_session_open_device_job( QDMI_Device_Session session, const char* jobId, QDMI_Device_Job* job) { if (session == nullptr || !session->initialized || jobId == nullptr || - jobId[0] == '\0' || job == nullptr) { + *jobId == '\0' || job == nullptr) { return QDMI_ERROR_INVALIDARGUMENT; } if (std::string_view{jobId} != "session-job") { @@ -222,7 +222,7 @@ extern "C" int TEST_SESSION_QDMI_device_session_open_device_job( } // The QDMI C API transfers this allocation through an opaque raw handle. // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - *job = new (std::nothrow) QDMI_Device_Job_impl_d{session}; + *job = new (std::nothrow) QDMI_Device_Job_impl_d{.session = session}; return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; } diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 11518bab28..3bed53850f 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -469,7 +469,7 @@ TEST_P(DriverTest, JobOpen) { } TEST(JobOpenTest, OpensExistingJobThroughClientApi) { - const auto device = + auto* const device = openTestDevice(MQT_CORE_QDMI_SESSION_DEVICE, "TEST_SESSION"); QDMI_Job job = nullptr; ASSERT_EQ(QDMI_device_open_job(device, "session-job", &job), QDMI_SUCCESS); From d8472eed4ecff744c05f454854675cff8c23f887 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 18:24:38 +0200 Subject: [PATCH 10/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Align=20job=20reopen?= =?UTF-8?q?ing=20with=20current=20providers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export the new source-level symbol from all built-in providers while keeping runtime loading compatible with older QDMI libraries. Assisted-by: GPT-5.6 via Codex --- cmake/ExternalDependencies.cmake | 4 ++-- src/qdmi/devices/dd/Device.cpp | 6 ++++++ src/qdmi/devices/na/Device.cpp | 6 ++++++ src/qdmi/devices/sc/Device.cpp | 5 +++++ test/qdmi/driver/test_driver.cpp | 16 ++++++++++++---- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index 986089d3fc..008d0b344d 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "0fd884b0afdd55883535f955822617aaa46bb0d2" # QDMI PR #485 +set(QDMI_REV "3716948044e23aa50c084732aae2cc3ee913014e" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") @@ -125,7 +125,7 @@ if(NOT TARGET spdlog::spdlog) cmake_dependent_option(SPDLOG_BUILD_SHARED "Build spdlog as shared library" ON "BUILD_MQT_CORE_SHARED_LIBS" OFF) FetchContent_Declare(spdlog URL ${SPDLOG_URL} FIND_PACKAGE_ARGS ${SPDLOG_VERSION}) - list(PREPEND FETCH_PACKAGES spdlog) + list(APPEND FETCH_PACKAGES spdlog) set(MQT_CORE_MANAGES_SPDLOG ON) endif() diff --git a/src/qdmi/devices/dd/Device.cpp b/src/qdmi/devices/dd/Device.cpp index 7a85a8038c..ae7789bbc0 100644 --- a/src/qdmi/devices/dd/Device.cpp +++ b/src/qdmi/devices/dd/Device.cpp @@ -844,6 +844,12 @@ int MQT_DDSIM_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } +int MQT_DDSIM_QDMI_device_session_open_device_job(MQT_DDSIM_QDMI_Device_Session, + const char*, + MQT_DDSIM_QDMI_Device_Job*) { + return QDMI_ERROR_NOTSUPPORTED; +} + void MQT_DDSIM_QDMI_device_job_free(MQT_DDSIM_QDMI_Device_Job job) { job->free(); } diff --git a/src/qdmi/devices/na/Device.cpp b/src/qdmi/devices/na/Device.cpp index a6a68d2204..32b80dbf58 100644 --- a/src/qdmi/devices/na/Device.cpp +++ b/src/qdmi/devices/na/Device.cpp @@ -684,6 +684,12 @@ int MQT_NA_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } +int MQT_NA_QDMI_device_session_open_device_job(MQT_NA_QDMI_Device_Session, + const char*, + MQT_NA_QDMI_Device_Job*) { + return QDMI_ERROR_NOTSUPPORTED; +} + void MQT_NA_QDMI_device_job_free(MQT_NA_QDMI_Device_Job job) { if (job != nullptr) { job->free(); diff --git a/src/qdmi/devices/sc/Device.cpp b/src/qdmi/devices/sc/Device.cpp index a62a7955d9..a9b17dab4c 100644 --- a/src/qdmi/devices/sc/Device.cpp +++ b/src/qdmi/devices/sc/Device.cpp @@ -470,6 +470,11 @@ int MQT_SC_QDMI_device_session_create_device_job( return session == nullptr ? QDMI_ERROR_INVALIDARGUMENT : session->createDeviceJob(job); } +int MQT_SC_QDMI_device_session_open_device_job(MQT_SC_QDMI_Device_Session, + const char*, + MQT_SC_QDMI_Device_Job*) { + return QDMI_ERROR_NOTSUPPORTED; +} void MQT_SC_QDMI_device_job_free(MQT_SC_QDMI_Device_Job job) { if (job != nullptr) { job->free(); diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 3bed53850f..c07bc1d770 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -265,6 +265,15 @@ class ChildDeviceLibrary final : public qdmi::DeviceLibrary { return driver.open(id); } +[[nodiscard]] auto openOwnedSessionTestDevice(const std::string_view id) + -> fomac::Device { + static_cast(qdmi::Driver::get().registerDeviceIfAbsent( + {.id = std::string{id}, + .library = MQT_CORE_QDMI_SESSION_DEVICE, + .prefix = "TEST_SESSION"})); + return fomac::Session::openDevice(id); +} + class DriverTest : public testing::TestWithParam { protected: QDMI_Session session = nullptr; @@ -469,8 +478,8 @@ TEST_P(DriverTest, JobOpen) { } TEST(JobOpenTest, OpensExistingJobThroughClientApi) { - auto* const device = - openTestDevice(MQT_CORE_QDMI_SESSION_DEVICE, "TEST_SESSION"); + const auto ownedDevice = openOwnedSessionTestDevice("test.open-job-client"); + const QDMI_Device device = ownedDevice; QDMI_Job job = nullptr; ASSERT_EQ(QDMI_device_open_job(device, "session-job", &job), QDMI_SUCCESS); ASSERT_NE(job, nullptr); @@ -497,8 +506,7 @@ TEST(JobOpenTest, OpensExistingJobThroughClientApi) { } TEST(FoMaCJobTest, OpensExistingJobs) { - const auto device = fomac::Session::createSessionlessDevice( - openTestDevice(MQT_CORE_QDMI_SESSION_DEVICE, "TEST_SESSION")); + const auto device = openOwnedSessionTestDevice("test.open-job-fomac"); const auto job = device.openJob("session-job"); EXPECT_EQ(job.getId(), "session-job"); } From 916a61f8388532754b6dc31a77d93b0a36434153 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 18:29:49 +0200 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=A7=AA=20Enforce=20reopened=20job?= =?UTF-8?q?=20state=20in=20provider=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model reopened handles separately so the test provider rejects parameter updates and resubmission as required by QDMI. Assisted-by: GPT-5.6 via Codex --- test/qdmi/driver/session_device.cpp | 11 ++++++++--- test/qdmi/driver/test_driver.cpp | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/test/qdmi/driver/session_device.cpp b/test/qdmi/driver/session_device.cpp index 54a6e0fdad..08fd379b77 100644 --- a/test/qdmi/driver/session_device.cpp +++ b/test/qdmi/driver/session_device.cpp @@ -29,6 +29,7 @@ struct QDMI_Device_Session_impl_d { struct QDMI_Device_Job_impl_d { QDMI_Device_Session session = nullptr; std::string id = "session-job"; + bool opened = false; }; namespace { @@ -222,14 +223,18 @@ extern "C" int TEST_SESSION_QDMI_device_session_open_device_job( } // The QDMI C API transfers this allocation through an opaque raw handle. // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - *job = new (std::nothrow) QDMI_Device_Job_impl_d{.session = session}; + *job = new (std::nothrow) + QDMI_Device_Job_impl_d{.session = session, .opened = true}; return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; } extern "C" int TEST_SESSION_QDMI_device_job_set_parameter( QDMI_Device_Job job, QDMI_Device_Job_Parameter /*parameter*/, size_t /*size*/, const void* /*value*/) { - return job == nullptr ? QDMI_ERROR_INVALIDARGUMENT : QDMI_SUCCESS; + if (job == nullptr) { + return QDMI_ERROR_INVALIDARGUMENT; + } + return job->opened ? QDMI_ERROR_BADSTATE : QDMI_SUCCESS; } extern "C" int TEST_SESSION_QDMI_device_job_query_property( @@ -246,7 +251,7 @@ extern "C" int TEST_SESSION_QDMI_device_job_submit(QDMI_Device_Job job) { if (job == nullptr || job->session == nullptr) { return QDMI_ERROR_INVALIDARGUMENT; } - return QDMI_SUCCESS; + return job->opened ? QDMI_ERROR_BADSTATE : QDMI_SUCCESS; } extern "C" int TEST_SESSION_QDMI_device_job_cancel(QDMI_Device_Job /*job*/) { diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index c07bc1d770..0b8e53809b 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -493,6 +493,11 @@ TEST(JobOpenTest, OpensExistingJobThroughClientApi) { nullptr), QDMI_SUCCESS); EXPECT_EQ(id, "session-job"); + const size_t numShots = 1; + EXPECT_EQ(QDMI_job_set_parameter(job, QDMI_JOB_PARAMETER_SHOTSNUM, + sizeof(numShots), &numShots), + QDMI_ERROR_BADSTATE); + EXPECT_EQ(QDMI_job_submit(job), QDMI_ERROR_BADSTATE); QDMI_job_free(job); EXPECT_EQ(QDMI_device_open_job(nullptr, "session-job", &job), From 1fa36e7211d9209ea88a01cf9d24fbaedc4477c8 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Wed, 5 Aug 2026 18:57:24 +0200 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=8E=A8=20Address=20C++=20lint=20ann?= =?UTF-8?q?otations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- src/qdmi/devices/dd/Device.cpp | 7 ++++--- src/qdmi/devices/na/Device.cpp | 7 ++++--- src/qdmi/devices/sc/Device.cpp | 7 ++++--- test/qdmi/driver/test_driver.cpp | 3 ++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/qdmi/devices/dd/Device.cpp b/src/qdmi/devices/dd/Device.cpp index ae7789bbc0..fee8130420 100644 --- a/src/qdmi/devices/dd/Device.cpp +++ b/src/qdmi/devices/dd/Device.cpp @@ -844,9 +844,10 @@ int MQT_DDSIM_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } -int MQT_DDSIM_QDMI_device_session_open_device_job(MQT_DDSIM_QDMI_Device_Session, - const char*, - MQT_DDSIM_QDMI_Device_Job*) { +int MQT_DDSIM_QDMI_device_session_open_device_job( + [[maybe_unused]] MQT_DDSIM_QDMI_Device_Session session, + [[maybe_unused]] const char* jobId, + [[maybe_unused]] MQT_DDSIM_QDMI_Device_Job* job) { return QDMI_ERROR_NOTSUPPORTED; } diff --git a/src/qdmi/devices/na/Device.cpp b/src/qdmi/devices/na/Device.cpp index 32b80dbf58..6b049c5b55 100644 --- a/src/qdmi/devices/na/Device.cpp +++ b/src/qdmi/devices/na/Device.cpp @@ -684,9 +684,10 @@ int MQT_NA_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } -int MQT_NA_QDMI_device_session_open_device_job(MQT_NA_QDMI_Device_Session, - const char*, - MQT_NA_QDMI_Device_Job*) { +int MQT_NA_QDMI_device_session_open_device_job( + [[maybe_unused]] MQT_NA_QDMI_Device_Session session, + [[maybe_unused]] const char* jobId, + [[maybe_unused]] MQT_NA_QDMI_Device_Job* job) { return QDMI_ERROR_NOTSUPPORTED; } diff --git a/src/qdmi/devices/sc/Device.cpp b/src/qdmi/devices/sc/Device.cpp index a9b17dab4c..5fb9faede4 100644 --- a/src/qdmi/devices/sc/Device.cpp +++ b/src/qdmi/devices/sc/Device.cpp @@ -470,9 +470,10 @@ int MQT_SC_QDMI_device_session_create_device_job( return session == nullptr ? QDMI_ERROR_INVALIDARGUMENT : session->createDeviceJob(job); } -int MQT_SC_QDMI_device_session_open_device_job(MQT_SC_QDMI_Device_Session, - const char*, - MQT_SC_QDMI_Device_Job*) { +int MQT_SC_QDMI_device_session_open_device_job( + [[maybe_unused]] MQT_SC_QDMI_Device_Session session, + [[maybe_unused]] const char* jobId, + [[maybe_unused]] MQT_SC_QDMI_Device_Job* job) { return QDMI_ERROR_NOTSUPPORTED; } void MQT_SC_QDMI_device_job_free(MQT_SC_QDMI_Device_Job job) { diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 0b8e53809b..2e28c60f08 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -479,7 +480,7 @@ TEST_P(DriverTest, JobOpen) { TEST(JobOpenTest, OpensExistingJobThroughClientApi) { const auto ownedDevice = openOwnedSessionTestDevice("test.open-job-client"); - const QDMI_Device device = ownedDevice; + QDMI_Device device = ownedDevice; QDMI_Job job = nullptr; ASSERT_EQ(QDMI_device_open_job(device, "session-job", &job), QDMI_SUCCESS); ASSERT_NE(job, nullptr); From 7702455d747c1d7a257aae20c286109a82e5a61a Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Sat, 8 Aug 2026 23:38:44 +0200 Subject: [PATCH 13/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Adopt=20the=20QDMI?= =?UTF-8?q?=20job=20retrieval=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: GPT-5.6 via Codex --- CHANGELOG.md | 7 ++--- bindings/fomac/fomac.cpp | 6 ++-- cmake/ExternalDependencies.cmake | 2 +- include/mqt-core/fomac/FoMaC.hpp | 8 +++--- include/mqt-core/qdmi/driver/Driver.hpp | 13 +++++---- python/mqt/core/fomac.pyi | 4 +-- src/fomac/FoMaC.cpp | 7 +++-- src/qdmi/devices/dd/Device.cpp | 2 +- src/qdmi/devices/na/Device.cpp | 2 +- src/qdmi/devices/sc/Device.cpp | 2 +- src/qdmi/driver/Driver.cpp | 13 +++++---- test/python/fomac/test_fomac.py | 10 ++++--- test/qdmi/driver/session_device.cpp | 2 +- test/qdmi/driver/test_driver.cpp | 37 +++++++++++++++---------- 14 files changed, 62 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4260d9eac8..8287e4256b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,8 @@ releases may include breaking changes. ### Added - 🐍 Start building CPython 3.15 wheels ([#2011]) ([**@denialhaag**]) -- ✨ Add support for retrieving existing QDMI jobs by ID in C++, Python, and the QDMI - driver ([#2008]) ([**@burgholzer**]) +- ✨ Add support for retrieving existing QDMI jobs by ID in C++, Python, and the + QDMI driver ([#2008]) ([**@burgholzer**]) - ✨ Add PennyLane support for gate-based QDMI devices ([#2005]) ([**@burgholzer**]) - ✨ Integrate QDMI devices as MLIR compiler targets across C++, Python, and @@ -723,11 +723,8 @@ for previous changelogs._ -<<<<<<< HEAD [#2011]: https://github.com/munich-quantum-toolkit/core/pull/2011 -======= [#2008]: https://github.com/munich-quantum-toolkit/core/pull/2008 ->>>>>>> f7fcb791d (📝 Add job reopening changelog entry) [#2007]: https://github.com/munich-quantum-toolkit/core/pull/2007 [#2006]: https://github.com/munich-quantum-toolkit/core/pull/2006 [#2005]: https://github.com/munich-quantum-toolkit/core/pull/2005 diff --git a/bindings/fomac/fomac.cpp b/bindings/fomac/fomac.cpp index d2e7330e62..b3047b7e78 100644 --- a/bindings/fomac/fomac.cpp +++ b/bindings/fomac/fomac.cpp @@ -471,12 +471,12 @@ when the custom slot is unsupported.)pb"); "Submits an exact byte payload to the device."); device.def( - "open_job", + "retrieve_job_by_id", [](const fomac::Device& self, const std::string& jobId) { - return self.openJob(jobId); + return self.retrieveJobById(jobId); }, "job_id"_a, nb::rv_policy::reference_internal, - "Opens an existing job by its device-provided ID."); + "Retrieves an existing job by its device-provided ID."); device.def("__repr__", [](const fomac::Device& dev) { return ""; diff --git a/cmake/ExternalDependencies.cmake b/cmake/ExternalDependencies.cmake index 008d0b344d..63ef3dc04f 100644 --- a/cmake/ExternalDependencies.cmake +++ b/cmake/ExternalDependencies.cmake @@ -93,7 +93,7 @@ set(QDMI_MINIMUM_VERSION 1.3.3 CACHE STRING "Minimum QDMI version") set(QDMI_VERSION 1.3.3 CACHE STRING "QDMI version") -set(QDMI_REV "3716948044e23aa50c084732aae2cc3ee913014e" # QDMI PR #485 +set(QDMI_REV "a884facd38a551086eef00c3116f1c8e9a09b9c2" # QDMI PR #485 CACHE STRING "QDMI identifier (tag, branch or commit hash)") set(QDMI_REPO_OWNER "Munich-Quantum-Software-Stack" CACHE STRING "QDMI repository owner (change when using a fork)") diff --git a/include/mqt-core/fomac/FoMaC.hpp b/include/mqt-core/fomac/FoMaC.hpp index f275d6b0a0..8fa80009b1 100644 --- a/include/mqt-core/fomac/FoMaC.hpp +++ b/include/mqt-core/fomac/FoMaC.hpp @@ -552,14 +552,14 @@ class Device { const std::optional& custom5 = std::nullopt) const; /** - * @brief Opens an existing job by its device-provided ID. + * @brief Retrieves an existing job by its device-provided ID. * @details Opening a job does not submit, clone, or modify the remote job. * The returned handle can be used to query its state and retrieve results. * @param jobId The nonempty opaque ID returned by @ref Job::getId. - * @throws std::runtime_error If the driver or device cannot open the job. - * @see QDMI_device_open_job + * @throws std::runtime_error If the driver or device cannot retrieve the job. + * @see QDMI_session_retrieve_job_by_id */ - [[nodiscard]] Job openJob(std::string_view jobId) const; + [[nodiscard]] Job retrieveJobById(std::string_view jobId) const; auto operator<=>(const Device&) const noexcept = default; diff --git a/include/mqt-core/qdmi/driver/Driver.hpp b/include/mqt-core/qdmi/driver/Driver.hpp index 48b86ce4b0..e56cc6a014 100644 --- a/include/mqt-core/qdmi/driver/Driver.hpp +++ b/include/mqt-core/qdmi/driver/Driver.hpp @@ -123,9 +123,10 @@ struct DeviceLibrary { /// Function pointer to @ref QDMI_device_session_create_device_job. decltype(QDMI_device_session_create_device_job)* device_session_create_device_job{}; - /// Optional function pointer to @ref QDMI_device_session_open_device_job. - decltype(QDMI_device_session_open_device_job)* - device_session_open_device_job{}; + /// Optional function pointer to @ref + /// QDMI_device_session_retrieve_device_job_by_id. + decltype(QDMI_device_session_retrieve_device_job_by_id)* + device_session_retrieve_device_job_by_id{}; /// Function pointer to @ref QDMI_device_job_free. decltype(QDMI_device_job_free)* device_job_free{}; /// Function pointer to @ref QDMI_device_job_set_parameter. @@ -273,10 +274,10 @@ struct QDMI_Device_impl_d { auto createJob(QDMI_Job* job) -> int; /** - * @brief Opens an existing job for the device. - * @see QDMI_device_open_job + * @brief Retrieves an existing job for the device. + * @see QDMI_session_retrieve_job_by_id */ - auto openJob(const char* jobId, QDMI_Job* job) -> int; + auto retrieveJobById(const char* jobId, QDMI_Job* job) -> int; /** * @brief Frees the job associated with the device. diff --git a/python/mqt/core/fomac.pyi b/python/mqt/core/fomac.pyi index 8b2b3e26e9..dc345817fa 100644 --- a/python/mqt/core/fomac.pyi +++ b/python/mqt/core/fomac.pyi @@ -369,8 +369,8 @@ class Device: ) -> Job: """Submits an exact byte payload to the device.""" - def open_job(self, job_id: str) -> Job: - """Opens an existing job by its device-provided ID.""" + def retrieve_job_by_id(self, job_id: str) -> Job: + """Retrieves an existing job by its device-provided ID.""" def __eq__(self, arg: object, /) -> bool: ... def __ne__(self, arg: object, /) -> bool: ... diff --git a/src/fomac/FoMaC.cpp b/src/fomac/FoMaC.cpp index dee784c54f..9e2f9e3b0e 100644 --- a/src/fomac/FoMaC.cpp +++ b/src/fomac/FoMaC.cpp @@ -407,11 +407,12 @@ Job Device::submitJob(const std::span program, return jobWrapper; } -Job Device::openJob(const std::string_view jobId) const { +Job Device::retrieveJobById(const std::string_view jobId) const { const std::string id{jobId}; QDMI_Job job = nullptr; - qdmi::throwIfError(QDMI_device_open_job(device_.get(), id.c_str(), &job), - "Opening job"); + qdmi::throwIfError( + QDMI_session_retrieve_job_by_id(device_.get(), id.c_str(), &job), + "Retrieving job"); return Job{job, device_}; } diff --git a/src/qdmi/devices/dd/Device.cpp b/src/qdmi/devices/dd/Device.cpp index fee8130420..2d387650a0 100644 --- a/src/qdmi/devices/dd/Device.cpp +++ b/src/qdmi/devices/dd/Device.cpp @@ -844,7 +844,7 @@ int MQT_DDSIM_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } -int MQT_DDSIM_QDMI_device_session_open_device_job( +int MQT_DDSIM_QDMI_device_session_retrieve_device_job_by_id( [[maybe_unused]] MQT_DDSIM_QDMI_Device_Session session, [[maybe_unused]] const char* jobId, [[maybe_unused]] MQT_DDSIM_QDMI_Device_Job* job) { diff --git a/src/qdmi/devices/na/Device.cpp b/src/qdmi/devices/na/Device.cpp index 6b049c5b55..1618a064dd 100644 --- a/src/qdmi/devices/na/Device.cpp +++ b/src/qdmi/devices/na/Device.cpp @@ -684,7 +684,7 @@ int MQT_NA_QDMI_device_session_create_device_job( return session->createDeviceJob(job); } -int MQT_NA_QDMI_device_session_open_device_job( +int MQT_NA_QDMI_device_session_retrieve_device_job_by_id( [[maybe_unused]] MQT_NA_QDMI_Device_Session session, [[maybe_unused]] const char* jobId, [[maybe_unused]] MQT_NA_QDMI_Device_Job* job) { diff --git a/src/qdmi/devices/sc/Device.cpp b/src/qdmi/devices/sc/Device.cpp index 5fb9faede4..97d5a64cbb 100644 --- a/src/qdmi/devices/sc/Device.cpp +++ b/src/qdmi/devices/sc/Device.cpp @@ -470,7 +470,7 @@ int MQT_SC_QDMI_device_session_create_device_job( return session == nullptr ? QDMI_ERROR_INVALIDARGUMENT : session->createDeviceJob(job); } -int MQT_SC_QDMI_device_session_open_device_job( +int MQT_SC_QDMI_device_session_retrieve_device_job_by_id( [[maybe_unused]] MQT_SC_QDMI_Device_Session session, [[maybe_unused]] const char* jobId, [[maybe_unused]] MQT_SC_QDMI_Device_Job* job) { diff --git a/src/qdmi/driver/Driver.cpp b/src/qdmi/driver/Driver.cpp index fa8fc32322..bac80e88de 100644 --- a/src/qdmi/driver/Driver.cpp +++ b/src/qdmi/driver/Driver.cpp @@ -142,7 +142,7 @@ DynamicDeviceLibrary::DynamicDeviceLibrary(const std::string& libName, LOAD_DYNAMIC_SYMBOL(device_session_set_parameter) // device job interface LOAD_DYNAMIC_SYMBOL(device_session_create_device_job) - LOAD_OPTIONAL_DYNAMIC_SYMBOL(device_session_open_device_job) + LOAD_OPTIONAL_DYNAMIC_SYMBOL(device_session_retrieve_device_job_by_id) LOAD_DYNAMIC_SYMBOL(device_job_free) LOAD_DYNAMIC_SYMBOL(device_job_set_parameter) LOAD_DYNAMIC_SYMBOL(device_job_query_property) @@ -405,16 +405,16 @@ auto QDMI_Device_impl_d::createJob(QDMI_Job* job) -> int { return QDMI_SUCCESS; } -auto QDMI_Device_impl_d::openJob(const char* const jobId, QDMI_Job* job) +auto QDMI_Device_impl_d::retrieveJobById(const char* const jobId, QDMI_Job* job) -> int { if (jobId == nullptr || *jobId == '\0' || job == nullptr) { return QDMI_ERROR_INVALIDARGUMENT; } - if (library_->device_session_open_device_job == nullptr) { + if (library_->device_session_retrieve_device_job_by_id == nullptr) { return QDMI_ERROR_NOTSUPPORTED; } QDMI_Device_Job deviceJob = nullptr; - const auto result = library_->device_session_open_device_job( + const auto result = library_->device_session_retrieve_device_job_by_id( deviceSession_, jobId, &deviceJob); if (result != QDMI_SUCCESS) { return result; @@ -826,11 +826,12 @@ int QDMI_device_create_job(QDMI_Device dev, QDMI_Job* job) { return dev->createJob(job); } -int QDMI_device_open_job(QDMI_Device dev, const char* jobId, QDMI_Job* job) { +int QDMI_session_retrieve_job_by_id(QDMI_Device dev, const char* jobId, + QDMI_Job* job) { if (dev == nullptr) { return QDMI_ERROR_INVALIDARGUMENT; } - return dev->openJob(jobId, job); + return dev->retrieveJobById(jobId, job); } void QDMI_job_free(QDMI_Job job) { diff --git a/test/python/fomac/test_fomac.py b/test/python/fomac/test_fomac.py index 4dd49cb73b..b8fb2f445e 100644 --- a/test/python/fomac/test_fomac.py +++ b/test/python/fomac/test_fomac.py @@ -586,10 +586,12 @@ def test_device_submit_job_preserves_num_shots(ddsim_device: Device) -> None: assert job3.num_shots == 1000 -def test_device_open_job_reports_unsupported_provider(ddsim_device: Device) -> None: - """Expose job reopening through Python without requiring DDSIM support.""" - with pytest.raises(RuntimeError, match=r"Opening job: Not supported\."): - ddsim_device.open_job("unknown") +def test_device_retrieve_job_by_id_reports_unsupported_provider( + ddsim_device: Device, +) -> None: + """Expose job retrieval through Python without requiring DDSIM support.""" + with pytest.raises(RuntimeError, match=r"Retrieving job: Not supported\."): + ddsim_device.retrieve_job_by_id("unknown") @pytest.fixture diff --git a/test/qdmi/driver/session_device.cpp b/test/qdmi/driver/session_device.cpp index 08fd379b77..42f9a3a37b 100644 --- a/test/qdmi/driver/session_device.cpp +++ b/test/qdmi/driver/session_device.cpp @@ -212,7 +212,7 @@ TEST_SESSION_QDMI_device_session_create_device_job(QDMI_Device_Session session, return *job == nullptr ? QDMI_ERROR_OUTOFMEM : QDMI_SUCCESS; } -extern "C" int TEST_SESSION_QDMI_device_session_open_device_job( +extern "C" int TEST_SESSION_QDMI_device_session_retrieve_device_job_by_id( QDMI_Device_Session session, const char* jobId, QDMI_Device_Job* job) { if (session == nullptr || !session->initialized || jobId == nullptr || *jobId == '\0' || job == nullptr) { diff --git a/test/qdmi/driver/test_driver.cpp b/test/qdmi/driver/test_driver.cpp index 2e28c60f08..72781f2608 100644 --- a/test/qdmi/driver/test_driver.cpp +++ b/test/qdmi/driver/test_driver.cpp @@ -465,24 +465,29 @@ TEST_P(DriverTest, JobCreate) { QDMI_ERROR_INVALIDARGUMENT); } -TEST_P(DriverTest, JobOpen) { +TEST_P(DriverTest, JobRetrieveById) { QDMI_Job job = nullptr; - const auto result = QDMI_device_open_job(device, "session-job", &job); + const auto result = + QDMI_session_retrieve_job_by_id(device, "session-job", &job); if (result == QDMI_ERROR_NOTSUPPORTED) { return; } ASSERT_EQ(result, QDMI_SUCCESS); ASSERT_NE(job, nullptr); QDMI_job_free(job); - EXPECT_EQ(QDMI_device_open_job(device, "", &job), QDMI_ERROR_INVALIDARGUMENT); - EXPECT_EQ(QDMI_device_open_job(device, "unknown", &job), QDMI_ERROR_NOTFOUND); + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "", &job), + QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "unknown", &job), + QDMI_ERROR_NOTFOUND); } -TEST(JobOpenTest, OpensExistingJobThroughClientApi) { - const auto ownedDevice = openOwnedSessionTestDevice("test.open-job-client"); +TEST(JobRetrieveByIdTest, RetrievesExistingJobThroughClientApi) { + const auto ownedDevice = + openOwnedSessionTestDevice("test.retrieve-job-client"); QDMI_Device device = ownedDevice; QDMI_Job job = nullptr; - ASSERT_EQ(QDMI_device_open_job(device, "session-job", &job), QDMI_SUCCESS); + ASSERT_EQ(QDMI_session_retrieve_job_by_id(device, "session-job", &job), + QDMI_SUCCESS); ASSERT_NE(job, nullptr); size_t size = 0; @@ -501,19 +506,21 @@ TEST(JobOpenTest, OpensExistingJobThroughClientApi) { EXPECT_EQ(QDMI_job_submit(job), QDMI_ERROR_BADSTATE); QDMI_job_free(job); - EXPECT_EQ(QDMI_device_open_job(nullptr, "session-job", &job), + EXPECT_EQ(QDMI_session_retrieve_job_by_id(nullptr, "session-job", &job), + QDMI_ERROR_INVALIDARGUMENT); + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, nullptr, &job), QDMI_ERROR_INVALIDARGUMENT); - EXPECT_EQ(QDMI_device_open_job(device, nullptr, &job), + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "", &job), QDMI_ERROR_INVALIDARGUMENT); - EXPECT_EQ(QDMI_device_open_job(device, "", &job), QDMI_ERROR_INVALIDARGUMENT); - EXPECT_EQ(QDMI_device_open_job(device, "session-job", nullptr), + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "session-job", nullptr), QDMI_ERROR_INVALIDARGUMENT); - EXPECT_EQ(QDMI_device_open_job(device, "unknown", &job), QDMI_ERROR_NOTFOUND); + EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "unknown", &job), + QDMI_ERROR_NOTFOUND); } -TEST(FoMaCJobTest, OpensExistingJobs) { - const auto device = openOwnedSessionTestDevice("test.open-job-fomac"); - const auto job = device.openJob("session-job"); +TEST(FoMaCJobTest, RetrievesExistingJobs) { + const auto device = openOwnedSessionTestDevice("test.retrieve-job-fomac"); + const auto job = device.retrieveJobById("session-job"); EXPECT_EQ(job.getId(), "session-job"); }