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
13 changes: 13 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM --platform=x86_64 python:3.11-bookworm

ENV TZ="Europe/Berlin"

RUN apt-get update -y && \
apt-get autoremove -y
RUN apt-get install -y software-properties-common bash-completion cmake build-essential iputils-ping rsync p7zip-full libuv1-dev git nlohmann-json3-dev librabbitmq-dev libboost-dev libgtest-dev pybind11-dev

RUN pip install uv

WORKDIR /home

CMD ["bash"]
9 changes: 9 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
{
"name": "MQSS Qiskit Adapter Development",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"build": {
"dockerfile": "Dockerfile"
}
}
Empty file removed mqss/__init__.py
Empty file.
22 changes: 12 additions & 10 deletions mqss/qiskit_adapter/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import os
from typing import List, Optional

from mqss_client import MQSSClient # type: ignore
from mqss.client import MQSSClient # type: ignore

from .backend import MQSSQiskitBackend

Expand All @@ -39,18 +39,20 @@ def __init__(
self,
token: str,
*,
hpcqc: Optional[bool] = None,
base_url: Optional[str] = None,
hpcqc: Optional[bool] = False,
base_url: Optional[str] = "",
) -> None:

is_hpcqc_env = os.getenv("MQSS_HPCQC_ENV", "False").lower() in [
"true",
"1",
"t",
]
# hpcqc gets priority over the environment variable

self.client = MQSSClient(
token=token,
base_url=base_url,
url_or_queue=base_url,
is_hpc=hpcqc if hpcqc is not None else is_hpcqc_env,
)

Expand Down Expand Up @@ -78,14 +80,14 @@ def backends(
Returns:
List[MQSSQiskitBackend]: List of backend instances
"""
resources = self.client.get_all_resources()
resources = self.client.resources
if resources is None:
return []
if name is not None and name not in resources:
if name is not None and not any([name==resource.name for resource in resources]):
raise ValueError(f"{name} is not available. ")
return [
MQSSQiskitBackend(self.client, _name, resources[_name])
for _name in resources
if (not online or resources[_name].online)
and (name is None or name == _name)
MQSSQiskitBackend(self.client, resource.name, resource)
for resource in resources
if (not online or resource.online)
and (name is None or name == resource.name)
]
22 changes: 10 additions & 12 deletions mqss/qiskit_adapter/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from typing import List, Optional, Union

from mqss_client import CircuitJobRequest, MQSSClient, ResourceInfo # type: ignore
from mqss.client import MQSSClient, Resource, CircuitJobRequest # type: ignore
from qiskit.circuit import QuantumCircuit # type: ignore
from qiskit.providers import BackendV2, Options # type: ignore
from qiskit.qasm2 import dumps as qasm2_str # type: ignore
Expand All @@ -42,22 +42,20 @@ def __init__(
self,
client: MQSSClient,
name: Optional[str] = None,
resource_info: Optional[ResourceInfo] = None,
resource: Optional[Resource] = None,
**kwargs,
):
super().__init__(**kwargs)
self.name = name
self.client = client
_resource_info = resource_info or (
self.client.get_resource_info(self.name) if name else None
)
resource = resource or (self.client.resource(self.name) if name else None)
self._coupling_map = None
self._target = None
if _resource_info is not None:
self._coupling_map = get_coupling_map(_resource_info)
self._target = get_target(_resource_info)
if resource is not None:
self._coupling_map = get_coupling_map(resource)
self._target = get_target(resource)

if self.name is not None and _resource_info is None:
if self.name is not None and resource is None:
raise ValueError(f"{self.name} is not available. ")

@classmethod
Expand Down Expand Up @@ -107,7 +105,7 @@ def num_pending_jobs(self) -> int:
Returns:
Number of pending jobs
"""
return self.client.get_num_pending_jobs(self.name)
return self.client.pending_job_count(self.name)

def run(
self,
Expand All @@ -134,7 +132,7 @@ def run(

if isinstance(run_input, QuantumCircuit):
_circuits = (
str([qasm3_str(run_input)]) if qasm3 else str([qasm2_str(run_input)])
str(qasm3_str(run_input)) if qasm3 else str(qasm2_str(run_input))
)
else:
_circuits = (
Expand All @@ -145,7 +143,7 @@ def run(
_circuit_format = "qasm3" if qasm3 else "qasm"

job_request = CircuitJobRequest(
circuits=_circuits,
circuit=_circuits,
circuit_format=_circuit_format,
resource_name=self.name,
shots=shots,
Expand Down
24 changes: 11 additions & 13 deletions mqss/qiskit_adapter/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
cancellation, status retrieval, and result fetching for MQSS backends using the MQSSClient.
"""

from mqss_client import CircuitJobRequest # type: ignore
from mqss_client import MQSSClient # type: ignore
from mqss_client import JobStatus as MQSSJobStatus # type: ignore
from mqss.client import MQSSClient, CircuitJobRequest
from qiskit.providers import JobStatus # type: ignore
from qiskit.providers import Backend, JobV1 # type: ignore
from qiskit.result import Counts, Result # type: ignore
Expand Down Expand Up @@ -56,16 +54,16 @@ def status(self) -> JobStatus:
([JobStatus](https://qiskit.org/documentation/stubs/qiskit.providers.JobStatus.html)).

"""
mqss_status = self.client.job_status(self.job_id(), self.job_request)
if mqss_status == MQSSJobStatus.PENDING:
mqss_status = self.client.job_status(self.job_request)
if mqss_status == "PENDING":
return JobStatus.INITIALIZING
if mqss_status == MQSSJobStatus.WAITING:
if mqss_status == "WAITING":
return JobStatus.QUEUED
if mqss_status == MQSSJobStatus.CANCELLED:
if mqss_status == "CANCELLED":
return JobStatus.CANCELLED
if mqss_status == MQSSJobStatus.FAILED:
if mqss_status == "FAILED":
return JobStatus.ERROR
if mqss_status == MQSSJobStatus.COMPLETED:
if mqss_status == "COMPLETED":
return JobStatus.DONE
raise RuntimeWarning(f"Unknown job status: {mqss_status}.")

Expand All @@ -76,11 +74,11 @@ def result(self) -> Result:
[Result](https://qiskit.org/documentation/stubs/qiskit.result.Result.html)
object for the job.
"""
res = self.client.wait_for_job_result(self.job_id(), self.job_request)
if isinstance(res.counts, list):
res_counts = res.counts
res = self.client.job_results(self.job_request, True)
if isinstance(res.results, list):
res_counts = res.results
else:
res_counts = [res.counts]
res_counts = [res.results]
result_dict = {
"backend_name": self.backend().name,
"backend_version": None,
Expand Down
43 changes: 24 additions & 19 deletions mqss/qiskit_adapter/mqss_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

"""MQP Resources"""

from mqss_client import ResourceInfo # type: ignore
from mqss.client import Resource # type: ignore
from qiskit.circuit.library import Measure # type: ignore
from qiskit.circuit.library import RXGate # type: ignore
from qiskit.circuit.library import ( # type: ignore
Expand All @@ -38,35 +38,40 @@
from qiskit.transpiler import CouplingMap, Target # type: ignore


def get_coupling_map(resource_info: ResourceInfo):
def get_coupling_map(resource: Resource):
"""Return CouplingMap for the backend"""

return (
CouplingMap(couplinglist=resource_info.connectivity)
if resource_info is not None and resource_info.connectivity is not None
CouplingMap(couplinglist=resource.coupling_map)
if resource is not None and resource.coupling_map is not None and len(resource.coupling_map) != 0
else None
)


def get_target(resource_info: ResourceInfo):
def get_target(resource: Resource):
"""Return Target for the backend"""

if resource is None or not resource.native_gateset:
return None

target = (
Target(num_qubits=resource_info.qubits)
if resource_info is not None and resource_info.instructions is not None
else None
)
target = Target(num_qubits=resource.qubit_count)

for gate in resource.native_gateset:
connections = (
{None: None}
if not gate.supported_qubits
else {tuple(qubits): None for qubits in gate.supported_qubits}
)

instruction_factory = instruction_map.get(gate.name)

if resource_info is not None and resource_info.instructions is not None:
assert target is not None
if instruction_factory is None:
print(
f"Warning: Instruction '{gate.name}' not found in the instruction_map."
)
continue

for _instruction, _connections in resource_info.instructions:
try:
target.add_instruction(instruction_map[_instruction](), _connections)
except KeyError:
print(
f"Warning: Instruction '{_instruction}' not found in the instruction_map."
)
target.add_instruction(instruction_factory(), connections)

return target

Expand Down
2 changes: 2 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def test_backend(session: Session, qiskit: str) -> None:
session.run("rm", "-rf", ".venv", external=True)
session.run("uv", "lock", "--upgrade-package", f"qiskit=={qiskit}", external=True)
session.run("uv", "sync", external=True)
session.run("uv", "pip", "install", "../MQSS-Client", external=True)
session.run("uv", "run", "pytest", "-v", "-s", "-m", "backend", external=True)


Expand All @@ -24,4 +25,5 @@ def test_job(session: Session, qiskit: str) -> None:
session.run("rm", "-rf", ".venv", external=True)
session.run("uv", "lock", "--upgrade-package", f"qiskit=={qiskit}", external=True)
session.run("uv", "sync", external=True)
session.run("uv", "pip", "install", "../MQSS-Client", external=True)
session.run("uv", "run", "pytest", "-v", "-s", "-m", "job", external=True)
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ dependencies = [
"requests>=2.32.3",
"python-decouple>=3.8",
"qiskit-qasm3-import>=0.5.1",
"mqss-client>=0.2.0",
]
# Sub-Dependency SciPy 1.9 supports Python 3.8-3.11
requires-python = ">=3.9,<3.14"
Expand Down
2 changes: 1 addition & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

# NOTE: change to current backend names
BACKENDS = ["QExa20"]
URL = "https://portal.quantum.lrz.de:4000"
URL = "https://portal.quantum.lrz.de:4000/v1/"


@pytest.mark.skipif(TOKEN is None, reason="MQSS token not provided")
Expand Down
2 changes: 1 addition & 1 deletion test/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"""Module to test the MQSS Qiskit Adapter"""

import pytest
from mqss_client import MQSSClient # type: ignore
from mqss.client import MQSSClient # type: ignore

from mqss.qiskit_adapter import MQSSQiskitBackend # type: ignore

Expand Down
2 changes: 1 addition & 1 deletion test/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"""Module to test the MQSS Qiskit Backend."""

import pytest
from mqss_client import MQSSClient # type: ignore
from mqss.client import MQSSClient # type: ignore
from qiskit import compiler # type: ignore
from qiskit.providers import JobStatus as QiskitJobStatus # type: ignore

Expand Down
Loading