From 75e6c56f9b95a3464440400f0830ff4bdb58dc23 Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Mon, 24 Aug 2026 13:27:27 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Initialize=20the=20Qiskit=20C=20?= =?UTF-8?q?API=20once?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Publish the vendored translation-unit-local function tables through thread-safe static initialization for nanobind 3 free-threaded bindings. Add concurrent import and export coverage. Assisted-by: GPT-5.6 Sol via Codex Signed-off-by: Simon Hofmann --- bindings/mlir/qiskit/Qiskit2_5.cpp | 18 ++++++++++-------- test/python/test_mlir_qiskit_translation.py | 13 +++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/bindings/mlir/qiskit/Qiskit2_5.cpp b/bindings/mlir/qiskit/Qiskit2_5.cpp index c45255ee4c..c803ae7c97 100644 --- a/bindings/mlir/qiskit/Qiskit2_5.cpp +++ b/bindings/mlir/qiskit/Qiskit2_5.cpp @@ -1903,16 +1903,18 @@ class NativeTranslation final : public VersionedTranslation { std::unique_ptr MQT_QISKIT_VERSION_FACTORY() { // NOLINT(misc-use-internal-linkage): declared in // the version registry. - if (qk_import() < 0) { - throwPythonError("failed to initialize the Qiskit " MQT_QISKIT_VERSION_LABEL - " C API"); - } - const auto version = qk_api_version(); - const auto major = (version >> 24U) & 0xffU; - const auto minor = (version >> 16U) & 0xffU; + static const auto VERSION = []() { + if (qk_import() < 0) { + throwPythonError( + "failed to initialize the Qiskit " MQT_QISKIT_VERSION_LABEL " C API"); + } + return qk_api_version(); + }(); + const auto major = (VERSION >> 24U) & 0xffU; + const auto minor = (VERSION >> 16U) & 0xffU; if (major != MQT_QISKIT_VERSION_EXPECTED_MAJOR || minor != MQT_QISKIT_VERSION_EXPECTED_MINOR || - (MQT_QISKIT_VERSION_EXACT_API != 0 && version != QISKIT_VERSION_HEX)) { + (MQT_QISKIT_VERSION_EXACT_API != 0 && VERSION != QISKIT_VERSION_HEX)) { throw std::runtime_error("Qiskit C API capsule version does not match the " "selected " MQT_QISKIT_VERSION_LABEL " translation"); diff --git a/test/python/test_mlir_qiskit_translation.py b/test/python/test_mlir_qiskit_translation.py index d9ac7569f8..02cad0652d 100644 --- a/test/python/test_mlir_qiskit_translation.py +++ b/test/python/test_mlir_qiskit_translation.py @@ -14,6 +14,7 @@ import re import subprocess import sys +from concurrent.futures import ThreadPoolExecutor from typing import TYPE_CHECKING import numpy as np @@ -105,6 +106,18 @@ ) +def test_native_api_initialization_supports_concurrent_translation() -> None: + """Initialize and reuse the native Qiskit API from concurrent translations.""" + + def _round_trip(_: int) -> str: + circuit = QuantumCircuit(1) + circuit.x(0) + return QCProgram.from_qiskit(circuit).to_qiskit().data[0].operation.name + + with ThreadPoolExecutor(max_workers=8) as executor: + assert list(executor.map(_round_trip, range(32))) == ["x"] * 32 + + @pytest.mark.parametrize("gate", STANDARD_GATES, ids=lambda gate: gate.name) def test_standard_gates_round_trip(gate: Gate) -> None: """Translate each supported gate family in both directions."""