Skip to content
Closed
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
23 changes: 6 additions & 17 deletions .agent/plans/package-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,9 @@ those defaults before any helper call.

## Validation

`test/cmake/installed_consumer/CMakeLists.txt` is one standalone regression. Run
it against an installed prefix, then build its device target:

```console
cmake -S test/cmake/installed_consumer -B build/installed-consumer -DCMAKE_PREFIX_PATH=<prefix>
cmake --build build/installed-consumer
```

It checks that package discovery preserves consumer settings and their cache
entries, including unset defaults, and builds a QDMI device with its colocated
manifest through the installed helper. The regression failed against the prior
installed config and passed after the change with QDMI 1.4.0.

Local validation passed: the `release-no-mlir` shared build and installation
with GCC 13, configuration with `MQT_CORE_INSTALL=OFF`, the installed consumer's
configuration and build, and repository lint. Full compiler and wheel
qualification belongs to the separate release validation work.
Historical validation passed with GCC 13 and QDMI 1.4.0: the `release-no-mlir`
shared build and installation, configuration with `MQT_CORE_INSTALL=OFF`, and
repository lint. A separate installed-consumer probe checked that package
discovery preserved consumer settings and cache entries and that the installed
helper built a QDMI device with its colocated manifest. That probe is not part
of the repository test suite.
2 changes: 1 addition & 1 deletion .github/workflows/slurm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:

- name: Build the MQT Core wheel
timeout-minutes: 15
run: uv build --wheel --out-dir test/slurm/dist
run: uv build --wheel --out-dir test/slurm/dist -Ccmake.define.DEPLOY=ON

- name: Test Slurm admission and QDMI execution
timeout-minutes: 15
Expand Down
10 changes: 6 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ if(MQT_CORE_INSTALL)
set(CMAKE_INSTALL_RPATH ${BASEPOINT} ${BASEPOINT}/${CMAKE_INSTALL_LIBDIR}
${BASEPOINT}/../${CMAKE_INSTALL_LIBDIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
if(APPLE)
# Avoid invalidating code signatures by rewriting Mach-O libraries during installation.
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif()
endif()

# add main library code
Expand Down Expand Up @@ -173,10 +176,9 @@ if(BUILD_MQT_CORE_MLIR)
endif()

if(BUILD_MQT_CORE_BINDINGS)
set(MQT_CORE_WHEEL_TARGETS mqt-core-bench-bindings mqt-core-bench-library mqt-core-dd
mqt-core-dd-bindings mqt-core-qdmi-bindings)
set(MQT_CORE_WHEEL_TARGETS mqt-core-bench-bindings mqt-core-dd-bindings mqt-core-qdmi-bindings)
if(BUILD_MQT_CORE_MLIR)
list(APPEND MQT_CORE_WHEEL_TARGETS mqt-core-bench mqt-core-mlir-bindings)
list(APPEND MQT_CORE_WHEEL_TARGETS mqt-cc mqt-core-bench mqt-core-mlir-bindings)
endif()
if(BUILD_MQT_CORE_MLIR AND BUILD_MQT_CORE_QDMI_DDSIM_DEVICE)
list(APPEND MQT_CORE_WHEEL_TARGETS mqt-core-qdmi-ddsim-device)
Expand Down
2 changes: 1 addition & 1 deletion bindings/dd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-dd-bindings)
INSTALL_DIR
.
LINK_LIBS
MQT::CoreDD)
MQT::CoreDDPython)

# install the Python stub file in editable mode for better IDE support
if(SKBUILD_STATE STREQUAL "editable")
Expand Down
2 changes: 1 addition & 1 deletion bindings/mlir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ if(NOT TARGET ${TARGET_NAME})
MLIRMQTDialect
MLIRMQTUtils
MLIRQCTranslationSupport
MLIRQCODDFunctionality)
MLIRQCODDFunctionalityPython)

if(MQT_QISKIT_CAPI_CANDIDATE_VERSION)
target_compile_definitions(
Expand Down
12 changes: 11 additions & 1 deletion cmake/AddMQTCoreLibrary.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ function(add_mqt_core_library name)

target_compile_features(${name} PUBLIC cxx_std_20)

target_link_libraries(${name} PRIVATE MQT::ProjectWarnings MQT::ProjectOptions)
target_link_libraries(${name}
PRIVATE "$<BUILD_LOCAL_INTERFACE:MQT::ProjectWarnings;MQT::ProjectOptions>")

if(ARG_HIDDEN_VISIBILITY)
set_target_properties(
Expand All @@ -53,6 +54,15 @@ function(add_mqt_core_library name)
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN 1
WINDOWS_EXPORT_ALL_SYMBOLS OFF)
elseif(WIN32)
get_target_property(target_type ${name} TYPE)
if(target_type STREQUAL "SHARED_LIBRARY")
set_target_properties(${name} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# CMake's automatic export scanner cannot read MSVC /GL objects.
set_target_properties(${name} PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF)
endif()
endif()
endif()

# Always compile with position-independent code to enable usage in shared libraries
Expand Down
6 changes: 4 additions & 2 deletions cmake/AddMQTPythonBinding.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function(add_mqt_python_binding package_name target_name)
${target_name}
# Enable free-threaded support
FREE_THREADED
# Keep computation in bindings optimized for speed.
NOMINSIZE
# Suppress compiler warnings from the nanobind library
NB_SUPPRESS_WARNINGS
# Use nanobind's shared runtime. Split mode enables the Stable ABI internally.
Expand All @@ -40,11 +42,11 @@ function(add_mqt_python_binding package_name target_name)

# Keep statically linked dependencies local.
if(APPLE)
# Restore the Python module namespace changed by HandleLLVMOptions, as in AddMLIRPython.
target_link_options(${target_name} PRIVATE "LINKER:-twolevel_namespace")
target_link_options(${target_name} PRIVATE "LINKER:-exported_symbol,_PyInit_${module_name}")
elseif(UNIX)
target_link_options(${target_name} PRIVATE "LINKER:--exclude-libs,ALL")
elseif(WIN32)
set_target_properties(${target_name} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS OFF)
endif()

# Add project libraries to the link libraries
Expand Down
30 changes: 6 additions & 24 deletions cmake/AddMQTQDMIDevice.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ function(mqt_copy_qdmi_runtime target)
if(NOT TARGET ${target})
message(FATAL_ERROR "Unknown QDMI application target: ${target}")
endif()
set_property(TARGET ${target} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE)
if(NOT (APPLE AND SKBUILD))
set_property(TARGET ${target} PROPERTY BUILD_WITH_INSTALL_RPATH FALSE)
endif()
set(devices ${ARGN})
if(NOT devices)
mqt_get_qdmi_device_targets(devices)
Expand Down Expand Up @@ -180,20 +182,9 @@ function(mqt_copy_qdmi_runtime target)
endif()
get_target_property(imported ${library_target} IMPORTED)
set(files "$<TARGET_FILE:${library}>")
if(WIN32)
if(imported)
# TARGET_RUNTIME_DLLS needs a local target to traverse imported dependencies.
string(MAKE_C_IDENTIFIER "${library_target}-dependencies" dependency_target)
if(NOT TARGET ${dependency_target})
add_library(${dependency_target} MODULE EXCLUDE_FROM_ALL
"${CMAKE_CURRENT_FUNCTION_LIST_FILE}")
set_property(TARGET ${dependency_target} PROPERTY LINKER_LANGUAGE CXX)
target_link_libraries(${dependency_target} PRIVATE ${library})
endif()
set(files "$<TARGET_RUNTIME_DLLS:${dependency_target}>")
else()
list(APPEND files "$<TARGET_RUNTIME_DLLS:${library}>")
endif()
if(UNIX AND library_type STREQUAL "SHARED_LIBRARY")
# Source installations may use a versioned SONAME in linked applications.
list(APPEND files "$<TARGET_SONAME_FILE:${library}>")
endif()
if(library IN_LIST devices)
get_target_property(manifest_name ${library_target} QDMI_MANIFEST_NAME)
Expand Down Expand Up @@ -236,14 +227,5 @@ function(mqt_copy_qdmi_runtime target)
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${files} "$<TARGET_FILE_DIR:${target}>"
COMMAND_EXPAND_LISTS)
if(NOT WIN32 AND imported)
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND
${CMAKE_COMMAND} "-DLIBRARY=$<TARGET_FILE:${library}>"
"-DDESTINATION=$<TARGET_FILE_DIR:${target}>" -P
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CopyQDMISharedDependencies.cmake")
endif()
endforeach()
endfunction()
21 changes: 0 additions & 21 deletions cmake/CopyQDMISharedDependencies.cmake

This file was deleted.

10 changes: 0 additions & 10 deletions cmake/StandardProjectSettings.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ if(DEFINED ENV{DEPLOY})
$ENV{DEPLOY}
CACHE BOOL "Use deployment configuration from environment" FORCE)
message(STATUS "Setting deployment configuration to '${DEPLOY}' from environment")
elseif(DEFINED ENV{CI})
set(DEPLOY
ON
CACHE BOOL "Set deployment configuration to ON for CI" FORCE)
message(STATUS "Setting deployment configuration to '${DEPLOY}' for CI")
endif()

# set deployment specific options
Expand Down Expand Up @@ -82,9 +77,4 @@ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION
${ipo_supported}
CACHE BOOL "Enable Interprocedural Optimization" FORCE)

# export all symbols by default on Windows
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
ON
CACHE BOOL "Export all symbols on Windows")

set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
19 changes: 12 additions & 7 deletions cmake/mqt-core-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@
include(CMakeFindDependencyMacro)
find_dependency(qdmi)

if(TARGET MQT::CoreDD)
return()
endif()

include("${CMAKE_CURRENT_LIST_DIR}/AddMQTPythonBinding.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/AddMQTQDMIDevice.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/PackageAddTest.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-runtime-targets.cmake")
set(mqt-core_Runtime_FOUND TRUE)

set(mqt-core_Development_FOUND FALSE)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/mqt-core-development-targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-development-targets.cmake")
set(mqt-core_Development_FOUND TRUE)
elseif("Development" IN_LIST mqt-core_FIND_COMPONENTS)
set(mqt-core_NOT_FOUND_MESSAGE
"The Development component requires an MQT Core source installation.")
endif()
check_required_components(mqt-core)

if(NOT mqt-core_FIND_QUIETLY)
message(STATUS "Found mqt-core version ${mqt-core_VERSION}")
Expand Down
7 changes: 4 additions & 3 deletions docs/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,9 @@ The output format changes the file name, but not the semantic case ID.

## C++ API

The installed `MQT::CoreBench` target provides typed parameters, references,
evaluation, instances, instance specifications, and manifests.
A source installation provides the `MQT::CoreBench` target with typed
parameters, references, evaluation, instances, instance specifications, and
manifests.

```cpp
#include "bench/Grover.hpp"
Expand All @@ -231,7 +232,7 @@ int main() {
```

```cmake
find_package(mqt-core CONFIG REQUIRED)
find_package(mqt-core CONFIG REQUIRED COMPONENTS Development)
target_link_libraries(my-benchmark PRIVATE MQT::CoreBench)
```

Expand Down
76 changes: 42 additions & 34 deletions docs/cpp_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,60 @@ The <a href="cpp/index.html">native C++ API reference</a> documents the
installed public headers, including decision diagrams, benchmarks, and QDMI. It
is generated from the same source revision as this guide.

## Use the DD library
## Use the wheel's native runtime

Create a two-qubit GHZ state, which is a Bell state, and print its amplitudes.
Save this as `main.cpp`:
The Python wheel supplies the QDMI driver, device bundles, and the `mqt-cc` and
`mqt-core-bench` executables. Its CMake package exposes the QDMI C interfaces;
C++ DD, QDMI client, and benchmark libraries require a source installation.

This application allocates a session through the builtin driver's C interface.
Save it as `main.cpp`:

```cpp
#include "dd/Edge.hpp"
#include "dd/Package.hpp"
#include "dd/StateGeneration.hpp"
#include <qdmi/client.h>

#include <iostream>

int main() {
dd::Package package(2);
const auto state = dd::makeGHZState(2, package);
for (const auto amplitude : dd::getVector(state)) {
std::cout << amplitude << '\n';
QDMI_Session session = nullptr;
if (QDMI_session_alloc(&session) != QDMI_SUCCESS) {
return 1;
}
package.decRef(state);
QDMI_session_free(session);
std::cout << "QDMI driver available\n";
}
```

The DD package owns its nodes. The state returned by `makeGHZState` holds a
reference until `decRef` releases it. Keep the package alive while using the
state. Converting a DD to a dense vector takes space exponential in the number
of qubits; this example has only four amplitudes.

Save the following as `CMakeLists.txt`:

```cmake
cmake_minimum_required(VERSION 3.28)
project(dd-example LANGUAGES CXX)
find_package(mqt-core CONFIG REQUIRED)
add_executable(dd-example main.cpp)
target_link_libraries(dd-example PRIVATE MQT::CoreDD)
project(qdmi-example LANGUAGES CXX)
find_package(mqt-core CONFIG REQUIRED COMPONENTS Runtime)
add_executable(qdmi-example main.cpp)
target_link_libraries(qdmi-example PRIVATE MQT::CoreQDMIDriver)
mqt_copy_qdmi_runtime(qdmi-example MQT::CoreQDMI_DDSIM_Device)
```

With the Python wheel installed in the active environment, CMake and Ninja
available, run:
With the wheel installed in the active environment, run:

```console
cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATH="$(mqt-core-cli --cmake_dir)"
cmake --build build
./build/dd-example
./build/qdmi-example
```

The last command is for a Unix shell; on Windows, run `build\dd-example.exe`.
The output has amplitude $1/\sqrt{2}$ at `00` and `11`, and zero at `01` and
`10`. For a separate C++ installation, point `CMAKE_PREFIX_PATH` at its install
prefix instead. See {doc}`installation` for source builds and other CMake
integration options.
On Windows, run `build\qdmi-example.exe`. The application prints
`QDMI driver available`. No LLVM/MLIR installation is required.

CMake also provides `MQT::mqt-cc` and `MQT::mqt-core-bench` imported executable
targets. Use them in custom commands, or run `mqt-cc` and `mqt-core-bench` from
the environment's command line.

```{code-cell} ipython3
:tags: [remove-cell]
from pathlib import Path
from tempfile import TemporaryDirectory
import math
import os
import subprocess

Expand All @@ -87,14 +84,25 @@ with TemporaryDirectory() as directory:
subprocess.run(
["cmake", "--build", str(root / "build")], check=True, stderr=subprocess.STDOUT
)
executable = root / "build" / ("dd-example.exe" if os.name == "nt" else "dd-example")
executable = root / "build" / ("qdmi-example.exe" if os.name == "nt" else "qdmi-example")
result = subprocess.run([str(executable)], check=True, capture_output=True, text=True)
amplitudes = [complex(*map(float, line.strip("()").split(","))) for line in result.stdout.splitlines()]
expected = [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)]
assert len(amplitudes) == len(expected)
assert all(abs(actual - ideal) < 1e-6 for actual, ideal in zip(amplitudes, expected))
assert result.stdout.strip() == "QDMI driver available"
```

## Use the C++ development libraries

Build and install MQT Core from source, then request the `Development`
component. It provides `MQT::CoreDD`, `MQT::CoreQDMI`, and `MQT::CoreBench`. The
DD library is static; compile consumers with a compatible C++ toolchain.

```cmake
find_package(mqt-core CONFIG REQUIRED COMPONENTS Development)
target_link_libraries(my-application PRIVATE MQT::CoreDD)
```

Point `CMAKE_PREFIX_PATH` at the source installation's prefix. See
{doc}`installation` for source builds and other CMake integration options.

## Extend the compiler or QIR runtime

The MLIR compiler and QIR runtime use source-tree C++ interfaces. They are not
Expand Down
Loading
Loading