Skip to content
Draft
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
30 changes: 30 additions & 0 deletions .agent/plans/qdmi-v14-metadata-cleanup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Adopt QDMI metadata removal

Status: implemented and locally validated; hosted CI remains the merge gate.

## Goal and scope

Remove Core's calibration-advisory accessor and the bundled devices' obsolete
pulse metadata after QDMI PRs #512 and #513 remove these properties. This is
Core 4.1 work, independent of driver replacement, program capabilities, and
multi-program jobs. It must not enter the Core 4.0 release.

## Decisions

Keep calibration-job submission and the calibration status: these are not the
removed advisory. Keep the existing program-format enum and job interfaces. Pin
the independent QDMI cleanup while developing; replace that pin with a released
QDMI 1.4 before publishing artifacts. Clients and devices must use matching
headers because the regular property values change.

The affected interfaces are in `include/mqt-core/qdmi/Client.hpp`,
`src/qdmi/Client.cpp`, and `bindings/qdmi/qdmi.cpp`. Bundled-device changes live
under `src/qdmi/devices/`. Remove only tests for the deleted API; preserve the
current optional-DDSIM build coverage and unrelated concurrency behavior.

## Validation

The release build and CTest passed (3,693 passed, one existing skip). All 249
QDMI Python tests passed with both bundled devices enabled. Stub generation,
lint, and C++ lint passed. Keep both bundled devices enabled for the full Python
suite; the stub-generation environment deliberately disables the SC device.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ releases may include breaking changes.

### Removed

- 馃挜 Remove the C++ `Device::getNeedsCalibration` and Python
`Device.needs_calibration` APIs, and adopt QDMI's removal of the obsolete
calibration-readiness and pulse-support metadata ([#2233]) ([**@burgholzer**])
- 馃挜 Remove `qc::QuantumComputation`, `MQT::CoreIR`, and `MQT::CoreQASM`. Use
compiler-backed QC/QCO APIs in v4 or the MQT Core v3 release series for legacy
code ([#2111], [#2112], [#2288]) ([**@burgholzer**], [**@simon1hofmann**])
Expand Down Expand Up @@ -907,6 +910,7 @@ for previous changelogs._
[#2257]: https://github.com/munich-quantum-toolkit/core/pull/2257
[#2246]: https://github.com/munich-quantum-toolkit/core/pull/2246
[#2240]: https://github.com/munich-quantum-toolkit/core/pull/2240
[#2233]: https://github.com/munich-quantum-toolkit/core/pull/2233
[#2232]: https://github.com/munich-quantum-toolkit/core/pull/2232
[#2228]: https://github.com/munich-quantum-toolkit/core/pull/2228
[#2224]: https://github.com/munich-quantum-toolkit/core/pull/2224
Expand Down
10 changes: 10 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ of changes including minor and patch releases, please refer to the

## [Unreleased]

### QDMI 1.4 metadata removal

MQT Core removes `Device::getNeedsCalibration` and `Device.needs_calibration`
after QDMI removes its calibration advisory. Bundled devices no longer report
pulse-support metadata. The `CALIBRATION` status and calibration-job submission
remain available; this change does not alter program formats or job APIs.

Rebuild clients, drivers, and devices against matching QDMI 1.4 headers because
the remaining regular device-property values are renumbered.

### Removal of the classic circuit representation

MQT Core 4 removes the complete classic circuit surface. This includes the C++
Expand Down
3 changes: 0 additions & 3 deletions bindings/qdmi/qdmi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,6 @@ text, so the device must receive it as exact bytes. Pass ``bytes`` to
device.def("coupling_map", &qdmi::Device::getCouplingMap,
"Returns the coupling map of the device as a list of site pairs.");

device.def("needs_calibration", &qdmi::Device::getNeedsCalibration,
"Returns whether the device needs calibration.");

device.def("queue_length", &qdmi::Device::getQueueLength,
"Returns the current queue length, or None if unavailable.");

Expand Down
6 changes: 3 additions & 3 deletions cmake/ExternalDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ if(BUILD_MQT_CORE_TESTS)
endif()

# cmake-format: off
set(QDMI_MINIMUM_VERSION 1.3.3
set(QDMI_MINIMUM_VERSION 1.4.0
CACHE STRING "Minimum QDMI version")
set(QDMI_VERSION 1.3.3
set(QDMI_VERSION 1.4.0
CACHE STRING "QDMI version")
set(QDMI_REV "18cfb67fd9042761d3005c2f8655751c1758f9c5" # v1.3.3
set(QDMI_REV "3557d75d87e56f8b9c69b64feace6b49995433bb" # PR #513
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)")
Expand Down
2 changes: 1 addition & 1 deletion docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -2101,7 +2101,7 @@ SKIP_FUNCTION_MACROS = YES
# the path). If a tag file is not located in the directory in which Doxygen is
# run, you must also specify the path to the tagfile here.

TAGFILES = _build/qdmi.tag=https://munich-quantum-software-stack.github.io/QDMI/v1.3.2/
TAGFILES = _build/qdmi.tag=https://munich-quantum-software-stack.github.io/QDMI/pr-preview/pr-513/

# When a file name is specified after GENERATE_TAGFILE, Doxygen will create a
# tag file that is based on the input files it reads. See section "Linking to
Expand Down
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,12 @@ def format_url(self, _e: Entry) -> HRef: # ruff:ignore[no-self-use]


cpp_api_tagfile = ("_build/doxygen/mqt-core.tag", "cpp/", "_build/doxygen/xml")
_qdmi_api_base = "https://munich-quantum-software-stack.github.io/QDMI/pr-preview/pr-513/"
qdmi_api_tagfile = (
"_build/qdmi.tag",
"https://munich-quantum-software-stack.github.io/QDMI/v1.3.3/",
_qdmi_api_base,
)
qdmi_api_tagfile_url = f"{_qdmi_api_base}qdmi.tag"

# -- Options for HTML output -------------------------------------------------

Expand Down
5 changes: 0 additions & 5 deletions docs/qir/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,3 @@ to Base formats: the JIT stops the selected entry point immediately before the
first call to a function marked `irreversible`, following the semantic boundary
defined by the Base Profile. It rejects other profiles and Base Profile programs
whose irreversible region is not terminal.

The generic submission APIs intentionally reject QDMI calibration and batch-job
formats. Calibration jobs do not carry a program, while batch jobs contain job
handles rather than serialized program bytes. Their format identifiers remain
available for capability discovery; they require dedicated typed APIs.
24 changes: 8 additions & 16 deletions include/mqt-core/qdmi/Client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,9 +544,6 @@ class Device {
[[nodiscard]] std::optional<std::vector<std::pair<Site, Site>>>
getCouplingMap() const;

/// @see QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION
[[nodiscard]] std::optional<size_t> getNeedsCalibration() const;

/// @see QDMI_DEVICE_PROPERTY_QUEUELENGTH
[[nodiscard]] std::optional<size_t> getQueueLength() const;

Expand Down Expand Up @@ -668,19 +665,14 @@ class Device {
const std::optional<CustomJobParameter>& custom4 = std::nullopt,
const std::optional<CustomJobParameter>& custom5 = std::nullopt) const;

/**
* @brief Triggers a calibration run.
* @details A device that reports a nonzero
* `QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION` is asked to calibrate by submitting
* a job in the `QDMI_PROGRAM_FORMAT_CALIBRATION` format. QDMI does not
* require a program for such a job, so the payload is optional; when it is
* present, the device defines what it means, which is usually a
* configuration for the run. A calibration run executes no circuit, so no
* shot count is set.
* @param program The calibration payload. An empty span or `std::nullopt`
* means that the job has no payload.
* @see QDMI_job_submit
*/
/// Triggers a calibration run in the `QDMI_PROGRAM_FORMAT_CALIBRATION`
/// format.
///
/// The payload is optional. When present, its meaning is device-specific.
/// A calibration run executes no circuit, so no shot count is set.
/// @param program The calibration payload. An empty span or `std::nullopt`
/// means that the job has no payload.
/// @see QDMI_job_submit
[[nodiscard]] Job submitCalibrationJob(
std::optional<std::span<const std::byte>> program = std::nullopt,
const std::optional<CustomJobParameter>& custom1 = std::nullopt,
Expand Down
4 changes: 0 additions & 4 deletions include/mqt-core/qdmi/common/Common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,6 @@ constexpr auto toString(const QDMI_Device_Property prop) -> const char* {
return "OPERATIONS";
case QDMI_DEVICE_PROPERTY_COUPLINGMAP:
return "COUPLING MAP";
case QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION:
return "NEEDS CALIBRATION";
case QDMI_DEVICE_PROPERTY_LENGTHUNIT:
return "LENGTH UNIT";
case QDMI_DEVICE_PROPERTY_LENGTHSCALEFACTOR:
Expand All @@ -384,8 +382,6 @@ constexpr auto toString(const QDMI_Device_Property prop) -> const char* {
return "DURATION SCALE FACTOR";
case QDMI_DEVICE_PROPERTY_MINATOMDISTANCE:
return "MIN ATOM DISTANCE";
case QDMI_DEVICE_PROPERTY_PULSESUPPORT:
return "PULSE SUPPORT";
case QDMI_DEVICE_PROPERTY_SUPPORTEDPROGRAMFORMATS:
return "SUPPORTED PROGRAM FORMATS";
case QDMI_DEVICE_PROPERTY_CHILDDEVICES:
Expand Down
3 changes: 0 additions & 3 deletions python/mqt/core/qdmi/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,6 @@ class Device:
def coupling_map(self) -> list[tuple[Device.Site, Device.Site]] | None:
"""Returns the coupling map of the device as a list of site pairs."""

def needs_calibration(self) -> int | None:
"""Returns whether the device needs calibration."""

def queue_length(self) -> int | None:
"""Returns the current queue length, or None if unavailable."""

Expand Down
5 changes: 0 additions & 5 deletions src/qdmi/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,6 @@ Device::getCouplingMap() const {
return couplingMap;
}

std::optional<size_t> Device::getNeedsCalibration() const {
return queryProperty<std::optional<size_t>>(
QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION);
}

std::optional<size_t> Device::getQueueLength() const {
return queryProperty<std::optional<size_t>>(QDMI_DEVICE_PROPERTY_QUEUELENGTH);
}
Expand Down
7 changes: 0 additions & 7 deletions src/qdmi/devices/dd/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,6 @@ auto Device::queryProperty(const QDMI_Device_Property prop, const size_t size,
status_.load(), prop, size, value, sizeRet)
ADD_SINGLE_VALUE_PROPERTY(QDMI_DEVICE_PROPERTY_QUBITSNUM, size_t, qubitsNum_,
prop, size, value, sizeRet)
// This device never needs calibration
ADD_SINGLE_VALUE_PROPERTY(QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION, size_t, 0,
prop, size, value, sizeRet)
// This device does not support pulse-level control
ADD_SINGLE_VALUE_PROPERTY(
QDMI_DEVICE_PROPERTY_PULSESUPPORT, QDMI_Device_Pulse_Support_Level,
QDMI_DEVICE_PULSE_SUPPORT_LEVEL_NONE, prop, size, value, sizeRet)
// Expose default length and time units
ADD_STRING_PROPERTY(QDMI_DEVICE_PROPERTY_LENGTHUNIT, "um", prop, size, value,
sizeRet)
Expand Down
5 changes: 0 additions & 5 deletions src/qdmi/devices/sc/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,6 @@ int MQT_SC_QDMI_Device_Session_impl_d::queryDeviceProperty(
sizeRet)
ADD_SINGLE_VALUE_PROPERTY(QDMI_DEVICE_PROPERTY_QUBITSNUM, size_t, qubitsNum,
property, size, value, sizeRet)
ADD_SINGLE_VALUE_PROPERTY(QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION, size_t, 0,
property, size, value, sizeRet)
ADD_SINGLE_VALUE_PROPERTY(
QDMI_DEVICE_PROPERTY_PULSESUPPORT, QDMI_Device_Pulse_Support_Level,
QDMI_DEVICE_PULSE_SUPPORT_LEVEL_NONE, property, size, value, sizeRet)
ADD_STRING_PROPERTY(QDMI_DEVICE_PROPERTY_DURATIONUNIT, durationUnit.c_str(),
property, size, value, sizeRet)
ADD_SINGLE_VALUE_PROPERTY(QDMI_DEVICE_PROPERTY_DURATIONSCALEFACTOR, double,
Expand Down
7 changes: 0 additions & 7 deletions test/python/qdmi/test_qdmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,6 @@ def test_device_coupling_map(device: Device) -> None:
assert all(isinstance(site, Device.Site) for pair in cm for site in pair)


def test_device_needs_calibration(device: Device) -> None:
"""Test that the device needs calibration is an integer."""
needs_cal = device.needs_calibration()
if needs_cal is not None:
assert isinstance(needs_cal, int)


def test_device_queue_length(device: Device) -> None:
"""Test that the optional device queue length is a non-negative integer."""
queue_length = device.queue_length()
Expand Down
8 changes: 0 additions & 8 deletions test/qdmi/driver/test_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -830,14 +830,6 @@ TEST_P(DriverTest, QuerySessionProperty) {
<< "Device must return `INVALIDARGUMENT` if the buffer is too small.";
}

TEST_P(DriverTest, QueryNeedsCalibration) {
size_t needsCalibration = 0;
const auto ret = QDMI_device_query_device_property(
device, QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION, sizeof(size_t),
&needsCalibration, nullptr);
EXPECT_EQ(ret, QDMI_SUCCESS);
EXPECT_THAT(needsCalibration, testing::AnyOf(0, 1));
}
constexpr std::array DEVICES{
"MQT SC Default QDMI Device",
#ifdef MQT_CORE_QDMI_HAS_DDSIM_DEVICE
Expand Down
6 changes: 0 additions & 6 deletions test/qdmi/test_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,6 @@ TEST(QDMITest, DevicePropertyToString) {
EXPECT_STREQ(qdmi::toString(QDMI_DEVICE_PROPERTY_OPERATIONS), "OPERATIONS");
EXPECT_STREQ(qdmi::toString(QDMI_DEVICE_PROPERTY_COUPLINGMAP),
"COUPLING MAP");
EXPECT_STREQ(qdmi::toString(QDMI_DEVICE_PROPERTY_NEEDSCALIBRATION),
"NEEDS CALIBRATION");
EXPECT_STREQ(qdmi::toString(QDMI_DEVICE_PROPERTY_LENGTHUNIT), "LENGTH UNIT");
EXPECT_STREQ(qdmi::toString(QDMI_DEVICE_PROPERTY_LENGTHSCALEFACTOR),
"LENGTH SCALE FACTOR");
Expand Down Expand Up @@ -512,10 +510,6 @@ TEST_P(DeviceTest, CouplingMap) {
EXPECT_NO_THROW(std::ignore = device.getCouplingMap());
}

TEST_P(DeviceTest, NeedsCalibration) {
EXPECT_NO_THROW(std::ignore = device.getNeedsCalibration());
}

#ifdef MQT_CORE_QDMI_HAS_DDSIM_DEVICE
TEST_F(DDSimulatorDeviceTest, QueueLengthIsUnavailable) {
EXPECT_EQ(device.getQueueLength(), std::nullopt);
Expand Down
Loading