Source code for iqm.qdmi.qiskit

# Copyright (c) 2025 - 2026 IQM Finland Oy
# All rights reserved.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://github.com/iqm-finland/QDMI-on-IQM/blob/main/LICENSE
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

"""Qiskit-facing integration for the IQM QDMI device library."""

from __future__ import annotations

import os
from pathlib import Path
from typing import TYPE_CHECKING, ClassVar

try:
    from mqt.core.plugins.qiskit.backend import QDMIBackend
    from mqt.core.qdmi.driver import DeviceDefinition, open_device, register_device_if_absent
except ImportError as e:
    msg = (
        "Failed to import Qiskit plugin. "
        "Ensure that `iqm-qdmi` is installed with the `qiskit` extra, e.g., via `uv pip install iqm-qdmi[qiskit]`."
    )
    raise ImportError(msg) from e

from . import IQM_QDMI_DEVICE_ID, IQM_QDMI_LIBRARY_PATH, IQM_QDMI_PREFIX
from .gates import MoveGate

if TYPE_CHECKING:
    from qiskit.circuit import Instruction

__all__ = ["IQMBackend"]

IQM_DEFAULT_BASE_URL = "https://resonance.iqm.tech"


def __dir__() -> list[str]:
    return __all__


[docs] class IQMBackend(QDMIBackend): """Qiskit backend for the packaged IQM QDMI device library. This backend loads the shared library distributed with `iqm-qdmi` and exposes it through MQT Core's Qiskit-compatible QDMI backend. Args: base_url: Base URL of the IQM service. Overrides `IQM_SERVER_URL`, its `IQM_BASE_URL` alias, and the registered device default when provided. token: Authentication token. Defaults to `IQM_TOKEN`. tokens_file: Path to an authentication file. Defaults to `IQM_TOKENS_FILE`. qc_id: Optional IQM quantum computer identifier. Defaults to `IQM_QC_ID`. qc_alias: Optional IQM quantum computer alias. Defaults to `IQM_QUANTUM_COMPUTER`, then its `IQM_QC_ALIAS` alias. """ #: MOVE is native to IQM's star-topology devices but absent from Qiskit's #: standard gate library, so the Target needs it supplied here. _EXTRA_GATES: ClassVar[dict[str, Instruction | type[Instruction]]] = {"move": MoveGate()} def __init__( self, *, base_url: str | None = None, token: str | None = None, tokens_file: str | os.PathLike[str] | None = None, qc_id: str | None = None, qc_alias: str | None = None, ) -> None: """Initialize the IQM Qiskit backend.""" resolved_base_url = base_url or os.getenv("IQM_SERVER_URL") or os.getenv("IQM_BASE_URL") or None resolved_token = token or os.getenv("IQM_TOKEN") tokens_file_value = tokens_file or os.getenv("IQM_TOKENS_FILE") resolved_tokens_file = Path(tokens_file_value) if tokens_file_value else None resolved_qc_id = qc_id or os.getenv("IQM_QC_ID") resolved_qc_alias = qc_alias or os.getenv("IQM_QUANTUM_COMPUTER") or os.getenv("IQM_QC_ALIAS") register_device_if_absent( DeviceDefinition( IQM_QDMI_DEVICE_ID, IQM_QDMI_LIBRARY_PATH, IQM_QDMI_PREFIX, base_url=IQM_DEFAULT_BASE_URL, ) ) device = open_device( IQM_QDMI_DEVICE_ID, base_url=resolved_base_url, token=resolved_token, auth_file=resolved_tokens_file, custom1=resolved_qc_id, custom2=resolved_qc_alias, ) super().__init__(device=device)