Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ releases may include breaking changes.

### Added

- ✨ Support retrieving existing jobs by ID through the QDMI client API and
expose optional device queue length and job queue position through the C++ and
Python FoMaC APIs ([#2010]) ([**@burgholzer**])
- ✨ Support retrieving existing jobs by ID through the QDMI client API and C++
and Python FoMaC APIs, and expose optional device queue length and job queue
position ([#2008], [#2010]) ([**@burgholzer**])
- 🐍 Start building CPython 3.15 wheels ([#2011]) ([**@denialhaag**])
- ✨ Add PennyLane support for gate-based QDMI devices ([#2005])
([**@burgholzer**])
Expand Down Expand Up @@ -728,6 +728,7 @@ for previous changelogs._
[#2026]: https://github.com/munich-quantum-toolkit/core/pull/2026
[#2011]: https://github.com/munich-quantum-toolkit/core/pull/2011
[#2010]: https://github.com/munich-quantum-toolkit/core/pull/2010
[#2008]: https://github.com/munich-quantum-toolkit/core/pull/2008
[#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
Expand Down
8 changes: 8 additions & 0 deletions bindings/fomac/fomac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,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(
"retrieve_job_by_id",
[](const fomac::Device& self, const std::string& jobId) {
return self.retrieveJobById(jobId);
},
"job_id"_a, nb::rv_policy::reference_internal,
"Retrieves an existing job by its device-provided ID.");

device.def("__repr__", [](const fomac::Device& dev) {
return "<Device name=\"" + dev.getName() + "\">";
});
Expand Down
10 changes: 10 additions & 0 deletions include/mqt-core/fomac/FoMaC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,16 @@ class Device {
const std::optional<CustomJobParameter>& custom4 = std::nullopt,
const std::optional<CustomJobParameter>& custom5 = std::nullopt) const;

/**
* @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 retrieve the job.
* @see QDMI_session_retrieve_job_by_id
*/
[[nodiscard]] Job retrieveJobById(std::string_view jobId) const;

auto operator<=>(const Device&) const noexcept = default;

private:
Expand Down
3 changes: 3 additions & 0 deletions python/mqt/core/fomac.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ class Device:
) -> Job:
"""Submits an exact byte payload to the device."""

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: ...

Expand Down
9 changes: 9 additions & 0 deletions src/fomac/FoMaC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ Job Device::submitJob(const std::span<const std::byte> program,
return jobWrapper;
}

Job Device::retrieveJobById(const std::string_view jobId) const {
const std::string id{jobId};
QDMI_Job job = nullptr;
qdmi::throwIfError(
QDMI_session_retrieve_job_by_id(device_.get(), id.c_str(), &job),
"Retrieving job");
return Job{job, device_};
}

void Device::setCustomJobParam(QDMI_Job job, const QDMI_Job_Parameter param,
const CustomJobParameter& value) {
std::visit(
Expand Down
7 changes: 7 additions & 0 deletions src/qdmi/devices/dd/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,13 @@ int MQT_DDSIM_QDMI_device_session_create_device_job(
return session->createDeviceJob(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) {
return QDMI_ERROR_NOTSUPPORTED;
}

void MQT_DDSIM_QDMI_device_job_free(MQT_DDSIM_QDMI_Device_Job job) {
job->free();
}
Expand Down
7 changes: 7 additions & 0 deletions src/qdmi/devices/na/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,13 @@ int MQT_NA_QDMI_device_session_create_device_job(
return session->createDeviceJob(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) {
return QDMI_ERROR_NOTSUPPORTED;
}

void MQT_NA_QDMI_device_job_free(MQT_NA_QDMI_Device_Job job) {
if (job != nullptr) {
job->free();
Expand Down
6 changes: 6 additions & 0 deletions src/qdmi/devices/sc/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ int MQT_SC_QDMI_device_session_create_device_job(
return session == nullptr ? QDMI_ERROR_INVALIDARGUMENT
: session->createDeviceJob(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) {
return QDMI_ERROR_NOTSUPPORTED;
}
void MQT_SC_QDMI_device_job_free(MQT_SC_QDMI_Device_Job job) {
if (job != nullptr) {
job->free();
Expand Down
8 changes: 8 additions & 0 deletions test/python/fomac/test_fomac.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,14 @@ def test_device_submit_job_preserves_num_shots(ddsim_device: Device) -> None:
assert job3.num_shots == 1000


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
def submitted_job(ddsim_device: Device) -> Job:
"""Fixture that provides a submitted job for testing.
Expand Down
3 changes: 3 additions & 0 deletions test/qdmi/driver/test_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,9 @@ TEST(DeviceRegistrationTest, RetrievesExistingJobs) {
EXPECT_EQ(QDMI_session_retrieve_job_by_id(device, "missing", &job),
QDMI_ERROR_NOTFOUND);
EXPECT_EQ(job, nullptr);

const auto retrievedJob = device.retrieveJobById("session-job");
EXPECT_EQ(retrievedJob.getId(), "session-job");
}

TEST(DeviceRegistrationTest, FreshChildDeviceRetainsItsRootSession) {
Expand Down
Loading