Skip to content

Commit

Permalink
✨ switch to mqt-core Python package
Browse files Browse the repository at this point in the history
Signed-off-by: burgholzer <burgholzer@me.com>
  • Loading branch information
burgholzer committed Sep 5, 2024
1 parent 6b5d2d1 commit dbaa9cb
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 133 deletions.
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ repos:
- numpy
- pytest
- rustworkx
- mqt.qcec
- mqt.core
- mqt.qcec @ git+https://github.com/cda-tum/mqt-qcec.git@use-mqt-core-package

# Check for spelling
- repo: https://github.com/crate-ci/typos
Expand Down
13 changes: 13 additions & 0 deletions cmake/ExternalDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ if(NOT Z3_FOUND)
endif()

if(BUILD_MQT_QMAP_BINDINGS)
# Manually detect the installed mqt-core package.
execute_process(
COMMAND "${Python_EXECUTABLE}" -m mqt.core --cmake_dir
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE mqt-core_DIR
ERROR_QUIET)

# Add the detected directory to the CMake prefix path.
if(mqt-core_DIR)
list(APPEND CMAKE_PREFIX_PATH "${mqt-core_DIR}")
message(STATUS "Found mqt-core package: ${mqt-core_DIR}")
endif()

if(NOT SKBUILD)
# Manually detect the installed pybind11 package.
execute_process(
Expand Down
22 changes: 22 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ def _run_tests(
posargs.append("--cov-config=pyproject.toml")

session.install(*BUILD_REQUIREMENTS, *install_args, env=env)

# install mqt.core from source to avoid ABI incompatibilities
session.install(
"--no-build-isolation",
"mqt.core @ git+https://github.com/cda-tum/mqt-core@shared-libs",
"--no-binary",
"mqt.core",
*install_args,
env={
"CMAKE_GENERATOR": "Ninja",
},
)

install_arg = f"-ve.[{','.join(_extras)}]"
session.install("--no-build-isolation", "--reinstall-package", "mqt.qmap", install_arg, *install_args, env=env)
session.run("pytest", *run_args, *posargs, env=env)
Expand Down Expand Up @@ -99,6 +112,15 @@ def docs(session: nox.Session) -> None:
serve = args.builder == "html" and session.interactive
extra_installs = ["sphinx-autobuild"] if serve else []
session.install(*BUILD_REQUIREMENTS, *extra_installs)

# install mqt.core from source to avoid ABI incompatibilities
session.install(
"--no-build-isolation",
"mqt.core @ git+https://github.com/cda-tum/mqt-core@shared-libs",
"--no-binary",
"mqt.core",
)

session.install("--no-build-isolation", "-ve.[docs]", "--reinstall-package", "mqt.qmap")
session.chdir("docs")

Expand Down
17 changes: 11 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[build-system]
requires = [
"scikit-build-core>=0.10.1",
"setuptools-scm>=7",
"pybind11>=2.13.5",
"scikit-build-core>=0.10.1",
"setuptools-scm>=7",
"pybind11>=2.13.5",
"mqt.core @ git+https://github.com/cda-tum/mqt-core.git@shared-libs",
]
build-backend = "scikit_build_core.build"

Expand Down Expand Up @@ -41,7 +42,7 @@ classifiers = [
]
requires-python = ">=3.8"
dependencies = [
"qiskit[qasm3-import]>=1.0.0",
"mqt.core[qiskit] @ git+https://github.com/cda-tum/mqt-core.git@shared-libs",
"rustworkx[all]>=0.14.0",
"importlib_resources>=5.0; python_version < '3.10'",
"typing_extensions>=4.6; python_version < '3.10'",
Expand Down Expand Up @@ -315,13 +316,17 @@ environment = { Z3_ROOT="/opt/python/cp311-cp311/lib/python3.11/site-packages/z3
before-all = "/opt/python/cp311-cp311/bin/pip install z3-solver==4.12.6"
repair-wheel-command = [
"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/python/cp311-cp311/lib/python3.11/site-packages/z3/lib",
"auditwheel repair -w {dest_dir} {wheel}",
"""auditwheel repair -w {dest_dir} {wheel} \
--exclude libmqt-core-ir.so.2.6 \
--exclude libmqt-core-circuit-optimizer.so.2.6 \
--exclude libmqt-core-na.so.2.6""",
]

[tool.cibuildwheel.macos]
environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" }
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} --ignore-missing-dependencies"

[tool.cibuildwheel.windows]
before-build = "pip install delvewheel>=1.7.3"
repair-wheel-command = "delvewheel repair -v -w {dest_dir} {wheel} --namespace-pkg mqt"
repair-wheel-command = """delvewheel repair -w {dest_dir} {wheel} --namespace-pkg mqt --no-dll \"mqt-core-ir.dll;mqt-core-circuit-optimizer.dll;mqt-core-na.dll\""""
environment = { CMAKE_GENERATOR = "Ninja", SKBUILD_CMAKE_ARGS="--fresh" }
33 changes: 22 additions & 11 deletions src/mqt/qmap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,30 @@

from __future__ import annotations

import os
import sys
from pathlib import Path

if sys.platform == "win32" and sys.version_info > (3, 8, 0) and "Z3_ROOT" in os.environ:
lib_path = Path(os.environ["Z3_ROOT"]) / "lib"
if lib_path.exists():
os.add_dll_directory(str(lib_path))
bin_path = Path(os.environ["Z3_ROOT"]) / "bin"
if bin_path.exists():
os.add_dll_directory(str(bin_path))
# under Windows, make sure to add the appropriate DLL directory to the PATH
if sys.platform == "win32":

def _dll_patch() -> None:
"""Add the DLL directory to the PATH."""
import os
import sysconfig
from pathlib import Path

bin_dir = Path(sysconfig.get_paths()["purelib"]) / "mqt" / "core" / "bin"
os.add_dll_directory(str(bin_dir))

if sys.version_info > (3, 8, 0) and "Z3_ROOT" in os.environ:
lib_path = Path(os.environ["Z3_ROOT"]) / "lib"
if lib_path.exists():
os.add_dll_directory(str(lib_path))
bin_path = Path(os.environ["Z3_ROOT"]) / "bin"
if bin_path.exists():
os.add_dll_directory(str(bin_path))

_dll_patch()
del _dll_patch

from ._version import version as __version__
from .clifford_synthesis import optimize_clifford, synthesize_clifford
Expand All @@ -39,7 +52,6 @@
MappingResults,
Method,
NeutralAtomHybridArchitecture,
QuantumComputation,
SwapReduction,
SynthesisConfiguration,
SynthesisResults,
Expand Down Expand Up @@ -67,7 +79,6 @@
"MappingResults",
"Method",
"NeutralAtomHybridArchitecture",
"QuantumComputation",
"SubarchitectureOrder",
"SwapReduction",
"SynthesisConfiguration",
Expand Down
25 changes: 8 additions & 17 deletions src/mqt/qmap/clifford_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,26 @@

from __future__ import annotations

from typing import Any
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from .compile import CircuitInputType

from qiskit import QuantumCircuit, qasm3
from qiskit.quantum_info import Clifford, PauliList
from qiskit.transpiler.layout import TranspileLayout

from mqt.core import load

from .compile import extract_initial_layout_from_qasm
from .pyqmap import (
CliffordSynthesizer,
QuantumComputation,
SynthesisConfiguration,
SynthesisResults,
Tableau,
)


def _import_circuit(circuit: str | QuantumCircuit | QuantumComputation) -> QuantumComputation:
"""Import a circuit from a string, a QuantumCircuit, or a QuantumComputation."""
if isinstance(circuit, QuantumCircuit):
return QuantumComputation.from_qiskit(circuit)
if isinstance(circuit, str):
if circuit.endswith(".qasm"):
return QuantumComputation.from_file(circuit)
return QuantumComputation.from_qasm_str(circuit)
return circuit


def _reverse_paulis(paulis: list[str]) -> list[str]:
return [s[0] + s[:0:-1] if s[0] in "+-" else s[::-1] for s in paulis]

Expand Down Expand Up @@ -84,11 +77,9 @@ def _circuit_from_qasm(qasm: str) -> QuantumCircuit:
"""Create a proper :class:`qiskit.QuantumCircuit` from a QASM string (including layout information)."""
circ = qasm3.loads(qasm)
layout = extract_initial_layout_from_qasm(qasm, circ.qregs)

circ._layout = TranspileLayout( # noqa: SLF001
initial_layout=layout, input_qubit_mapping=layout.get_virtual_bits()
)

return circ


Expand Down Expand Up @@ -138,7 +129,7 @@ def synthesize_clifford(


def optimize_clifford(
circuit: str | QuantumCircuit | QuantumComputation,
circuit: CircuitInputType,
initial_tableau: str | Clifford | PauliList | Tableau | None = None,
include_destabilizers: bool = False,
**kwargs: Any, # noqa: ANN401
Expand Down Expand Up @@ -168,7 +159,7 @@ def optimize_clifford(
"""
config = _config_from_kwargs(kwargs)

qc = _import_circuit(circuit)
qc = load(circuit)
if initial_tableau is not None:
synthesizer = CliffordSynthesizer(_import_tableau(initial_tableau, include_destabilizers), qc)
else:
Expand Down
15 changes: 12 additions & 3 deletions src/mqt/qmap/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@

from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Union

from qiskit import QuantumCircuit, QuantumRegister, qasm3
from qiskit.transpiler import Layout, TranspileLayout

if TYPE_CHECKING:
from os import PathLike

from qiskit.providers import Backend
from qiskit.providers.models import BackendProperties
from qiskit.transpiler.target import Target

from mqt.core.ir import QuantumComputation

from .visualization import SearchVisualizer

CircuitInputType = Union[QuantumComputation, str, PathLike[str], QuantumCircuit]

from mqt.core import load

from .load_architecture import load_architecture
from .load_calibration import load_calibration
from .pyqmap import (
Expand Down Expand Up @@ -59,7 +67,7 @@ def extract_initial_layout_from_qasm(qasm: str, qregs: list[QuantumRegister]) ->


def compile( # noqa: A001
circ: QuantumCircuit | str,
circ: CircuitInputType,
arch: str | Arch | Architecture | Backend | None,
calibration: str | BackendProperties | Target | None = None,
method: str | Method = "heuristic",
Expand Down Expand Up @@ -182,7 +190,8 @@ def compile( # noqa: A001
config.lookaheads = lookaheads
config.lookahead_factor = lookahead_factor

results = map(circ, architecture, config)
qc = load(circ)
results = map(qc, architecture, config)

circ = qasm3.loads(results.mapped_circuit)
layout = extract_initial_layout_from_qasm(results.mapped_circuit, circ.qregs)
Expand Down
17 changes: 5 additions & 12 deletions src/mqt/qmap/pyqmap.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, ClassVar, overload

from qiskit import QuantumCircuit
from mqt.core.ir import QuantumComputation

class Arch:
__members__: ClassVar[dict[Arch, int]] = ... # read-only
Expand Down Expand Up @@ -393,7 +393,7 @@ class SwapReduction:
@property
def value(self) -> int: ...

def map(circ: str | QuantumCircuit, arch: Architecture, config: Configuration) -> MappingResults: ... # noqa: A001
def map(circ: QuantumComputation, arch: Architecture, config: Configuration) -> MappingResults: ... # noqa: A001

class TargetMetric:
__members__: ClassVar[dict[TargetMetric, int]] = ... # read-only
Expand Down Expand Up @@ -488,15 +488,6 @@ class SynthesisResults:
@property
def two_qubit_gates(self) -> int: ...

class QuantumComputation:
def __init__(self) -> None: ...
@staticmethod
def from_file(file: str) -> QuantumComputation: ...
@staticmethod
def from_qasm_str(qasm: str) -> QuantumComputation: ...
@staticmethod
def from_qiskit(circuit: QuantumCircuit) -> QuantumComputation: ...

class Tableau:
@overload
def __init__(self, n: int, include_stabilizers: bool = False) -> None: ...
Expand Down Expand Up @@ -586,7 +577,9 @@ class HybridNAMapper:
def get_init_hw_pos(self) -> dict[int, int]: ...
def get_mapped_qc(self) -> str: ...
def get_mapped_qc_aod(self) -> str: ...
def map(self, circ: object, initial_mapping: InitialCircuitMapping = ..., verbose: bool = ...) -> None: ...
def map(
self, circ: QuantumComputation, initial_mapping: InitialCircuitMapping = ..., verbose: bool = ...
) -> None: ...
def map_qasm_file(
self, filename: str, initial_mapping: InitialCircuitMapping = ..., verbose: bool = ...
) -> None: ...
Expand Down
12 changes: 10 additions & 2 deletions src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ endif()
list(APPEND CMAKE_INSTALL_RPATH ${BASEPOINT} ${BASEPOINT}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
list(
APPEND
CMAKE_INSTALL_RPATH
${BASEPOINT}/../core/${CMAKE_INSTALL_LIBDIR}
${BASEPOINT}/../core/lib
${BASEPOINT}/../core/lib64
${BASEPOINT}/../../core/${CMAKE_INSTALL_LIBDIR}
${BASEPOINT}/../../core/lib
${BASEPOINT}/../../core/lib64)

pybind11_add_module(
pyqmap
Expand All @@ -21,10 +30,9 @@ target_link_libraries(
PRIVATE MQT::QMapExact
MQT::QMapHeuristic
MQT::QMapCliffordSynthesis
MQT::CorePython
MQT::QMapHybrid
MQT::ProjectOptions
MQT::ProjectWarnings
MQT::QMapHybrid
pybind11_json)

# Install directive for scikit-build-core
Expand Down
Loading

0 comments on commit dbaa9cb

Please sign in to comment.