Skip to content
This repository has been archived by the owner on Jun 17, 2024. It is now read-only.

Commit

Permalink
feat: Migration of providers AWS, Azure, T-Systems and IBM to Qiskit 1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Wagner committed Mar 28, 2024
1 parent c5b13fc commit 7b7e328
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 54 deletions.
18 changes: 10 additions & 8 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ channels:
dependencies:
- python=3.9
- pip>=21.1.3
- pydantic=1.9.0
- pydantic==2.5.0
- pip:
## dev dependencies
- qiskit==0.44.1
- qiskit-ibm-runtime==0.17.0
- qiskit-ibm-provider==0.7.2
- qiskit==1.0.2
- qiskit-ibm-runtime==0.21.2
- qiskit-ibm-provider==0.10.0
- setuptools
- pytest
- pytest-cov
Expand All @@ -21,11 +21,13 @@ dependencies:
## prod dependencies
- requests
# aws braket
- amazon-braket-default-simulator==1.21.0
- amazon-braket-schemas==1.21.0
# we need the latest dev version as this fixes the issue with the Rigetti's qubit ids
#- git+https://github.com/qiskit-community/qiskit-braket-provider.git@main
- qiskit-braket-provider==0.2.0
- git+https://github.com/qiskit-community/qiskit-braket-provider.git@main
#- qiskit-braket-provider==0.2.0
# azure quantum
- azure-quantum[qiskit]==0.28.*
- azure-quantum[qiskit]==2.0.0.dev1
- qiskit-ionq==0.5.0
# dwave
- dwave-ocean-sdk==6.4.1
- dwave-ocean-sdk==6.9.0
28 changes: 17 additions & 11 deletions planqk/qiskit/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from abc import ABC
from copy import copy

from qiskit.circuit import Delay, Parameter
from qiskit.circuit import Measure
from qiskit.providers import BackendV2, Provider
from qiskit.providers.models import QasmBackendConfiguration, GateConfig
Expand Down Expand Up @@ -57,6 +56,7 @@ def __init__( # pylint: disable=too-many-arguments
self._backend_info = backend_info
self._target = self._planqk_backend_to_target()
self._configuration = self._planqk_backend_dto_to_configuration()
self._instance = None

def _planqk_backend_to_target(self) -> Target:
"""Converts properties of a PlanQK actual into Qiskit Target object.
Expand All @@ -77,26 +77,31 @@ def _planqk_backend_to_target(self) -> Target:

single_qubit_props = adapter.single_qubit_gate_props(qubits, is_simulator)
multi_qubit_props = adapter.multi_qubit_gate_props(qubits, connectivity, is_simulator)
for gate in configuration.gates:
name = gate.name
gate = adapter.op_to_instruction(name, is_simulator)
gates_names = {gate.name.lower() for gate in configuration.gates}
for gate in gates_names:
gate = adapter.to_gate(gate, is_simulator)

if gate is None:
continue

if gate.num_qubits == 1:
target.add_instruction(gate, single_qubit_props)
target.add_instruction(instruction=gate, properties=single_qubit_props)
elif gate.num_qubits > 1:
target.add_instruction(gate, multi_qubit_props)
target.add_instruction(instruction=gate, properties=multi_qubit_props)
elif gate.num_qubits == 0 and single_qubit_props == {None: None}:
# For gates without qubit number qargs can not be determined
target.add_instruction(gate, {None: None})
target.add_instruction(instruction=gate, properties={None: None})

target.add_instruction(Measure(), single_qubit_props)

if "delay" in configuration.instructions and "delay" not in target:
# gate_props = {None: None} if is_simulator else single_qubit_gate_props()
target.add_instruction(Delay(Parameter("t")), single_qubit_props)
non_gate_instructions = set(configuration.instructions).difference(gates_names).difference({'measure'})
for non_gate_instruction_name in non_gate_instructions:
instruction = adapter.to_non_gate_instruction(non_gate_instruction_name, is_simulator)
if instruction is not None:
if instruction.has_single_gate_props:
target.add_instruction(instruction, single_qubit_props)
else:
target.add_instruction(instruction=instruction, name=non_gate_instruction_name)

return target

Expand Down Expand Up @@ -129,7 +134,8 @@ def _planqk_backend_dto_to_configuration(self) -> QasmBackendConfiguration:

def _get_gate_config_from_target(self, name) -> GateConfig:
operations = [operation for operation in self._target.operations
if operation.name.casefold() == name.casefold()]
if isinstance(operation.name, str) # Filters out the IBM conditional instructions having no name
and operation.name.casefold() == name.casefold()]
if len(operations) == 1:
operation = operations[0]
return GateConfig(
Expand Down
5 changes: 2 additions & 3 deletions planqk/qiskit/job.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from typing import Optional

from planqk.qiskit.client.client import _PlanqkClient
from planqk.qiskit.client.job_dtos import JobDto
from qiskit.providers import JobV1, JobStatus, Backend
from qiskit.qobj import QobjExperimentHeader
from qiskit.result import Result
from qiskit.result.models import ExperimentResult, ExperimentResultData

from planqk.qiskit.client.client import _PlanqkClient
from planqk.qiskit.client.job_dtos import JobDto

JobStatusMap = {
"CREATED": JobStatus.INITIALIZING,
"PENDING": JobStatus.QUEUED,
Expand Down
15 changes: 14 additions & 1 deletion planqk/qiskit/providers/adapter.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
from typing import Optional, List

from qiskit.circuit import Gate, Delay, Parameter, Measure
from qiskit.circuit import Instruction as QiskitInstruction

from planqk.qiskit.client.backend_dtos import PROVIDER, QubitDto, ConnectivityDto


class ProviderAdapter:
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
non_gate_instr_mapping = {
"delay": Delay(Parameter("t")),
"measure": Measure(),
}

def to_gate(self, name: str, is_simulator: bool = False) -> Optional[Gate]:
pass

def to_non_gate_instruction(self, name: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
instr = self.non_gate_instr_mapping.get(name, None)
if instr is not None:
instr.has_single_gate_props = True
return instr
return None

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
pass

Expand Down
8 changes: 4 additions & 4 deletions planqk/qiskit/providers/aws_adapter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional, List

from qiskit.circuit import Instruction as QiskitInstruction
from qiskit.circuit import Gate
from qiskit_braket_provider.providers.adapter import _GATE_NAME_TO_QISKIT_GATE

import planqk.qiskit.providers.adapter as adapter
Expand All @@ -10,9 +10,9 @@
class AwsAdapter(adapter.ProviderAdapter):
"""Adapter for AWS Braket backend."""

def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
operation = operation.lower()
gate = _GATE_NAME_TO_QISKIT_GATE.get(operation, None)
def to_gate(self, name: str, is_simulator: bool = False) -> Optional[Gate]:
name = name.lower()
gate = _GATE_NAME_TO_QISKIT_GATE.get(name, None)
# Braket quantum backends only support 1 and 2 qubit gates
return gate if (gate and gate.num_qubits < 3) or is_simulator else None

Expand Down
9 changes: 4 additions & 5 deletions planqk/qiskit/providers/azure_adapter.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from typing import Optional, List

from qiskit.circuit import Instruction as QiskitInstruction, Gate

from planqk.qiskit.client.backend_dtos import QubitDto, ConnectivityDto
from planqk.qiskit.providers.adapter import ProviderAdapter
from qiskit.circuit import Gate


class AzureAdapter(ProviderAdapter):
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
operation = operation.lower()
return Gate(operation, 0, [])
def to_gate(self, name: str, is_simulator: bool = False) -> Optional[Gate]:
name = name.lower()
return Gate(name, 0, [])

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
return {None: None}
Expand Down
25 changes: 21 additions & 4 deletions planqk/qiskit/providers/ibm/ibm_adapter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional, List

from qiskit.circuit import Instruction as QiskitInstruction, Gate
from qiskit.circuit import Gate, IfElseOp, WhileLoopOp, ForLoopOp, SwitchCaseOp, Instruction
from qiskit.circuit import Parameter, Reset
from qiskit.circuit.library import IGate, SXGate, XGate, CXGate, RZGate, ECRGate, CZGate

Expand All @@ -18,11 +18,28 @@
"cz": CZGate(),
}

qiskit_control_flow_mapping = {
"if_else": IfElseOp,
"while_loop": WhileLoopOp,
"for_loop": ForLoopOp,
"switch_case": SwitchCaseOp,
}


class IbmAdapter(ProviderAdapter):
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
operation = operation.lower()
return ibm_name_mapping.get(operation, None) or Gate(operation, 0, [])

def to_gate(self, name: str, is_simulator: bool = False) -> Optional[Gate]:
name = name.lower()

return ibm_name_mapping.get(name, None) or Gate(name, 0, [])

def to_non_gate_instruction(self, name: str, is_simulator: bool = False) -> Optional[Instruction]:
if name in qiskit_control_flow_mapping:
instr = qiskit_control_flow_mapping[name]
instr.has_single_gate_props = False
return instr

return super().to_non_gate_instruction(name, is_simulator)

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
return {None: None} if is_simulator else {(int(qubit.id),): None for qubit in qubits}
Expand Down
3 changes: 1 addition & 2 deletions planqk/qiskit/providers/ibm/ibm_backend.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from qiskit.qobj.utils import MeasLevel, MeasReturnType

from planqk.qiskit import PlanqkBackend
from planqk.qiskit.options import OptionsV2
from qiskit.qobj.utils import MeasLevel, MeasReturnType


class PlanqkIbmBackend(PlanqkBackend):
Expand Down
2 changes: 1 addition & 1 deletion planqk/qiskit/providers/job_input_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class UnsupportedFormatException(Exception):
pass


def convert_to_backend_input(supported_input_formats: List[INPUT_FORMAT], circuit, backend, options=None) \
def convert_to_backend_input(supported_input_formats: List[INPUT_FORMAT], circuit, backend=None, options=None) \
-> Tuple[INPUT_FORMAT, dict]:
for input_format in supported_input_formats:
convert_circuit = input_format_converter_factory.get(input_format)
Expand Down
13 changes: 6 additions & 7 deletions planqk/qiskit/providers/qryd/qryd_adapter.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from typing import Optional, List

from qiskit.circuit import Instruction as QiskitInstruction, Parameter, Gate
from qiskit.circuit.library import PhaseGate, RGate, RXGate, RYGate, HGate, RZGate, UGate, XGate, YGate, ZGate, SXGate, \
SXdgGate, CXGate, CYGate, CZGate, CPhaseGate, SwapGate, iSwapGate

import planqk.qiskit.providers.adapter as adapter
from planqk.qiskit.client.backend_dtos import QubitDto, ConnectivityDto
from planqk.qiskit.providers.qryd.pcp_gate import PCPGate
from planqk.qiskit.providers.qryd.pcz_gate import PCZGate
from qiskit.circuit import Parameter, Gate
from qiskit.circuit.library import PhaseGate, RGate, RXGate, RYGate, HGate, RZGate, UGate, XGate, YGate, ZGate, SXGate, \
SXdgGate, CXGate, CYGate, CZGate, CPhaseGate, SwapGate, iSwapGate

qryd_gate_name_mapping = {
"p": PhaseGate(Parameter("lambda")),
Expand All @@ -34,9 +33,9 @@


class QrydAdapter(adapter.ProviderAdapter):
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
operation = operation.lower()
return qryd_gate_name_mapping.get(operation, None) or Gate(operation, 0, [])
def to_gate(self, name: str, is_simulator: bool = False) -> Optional[Gate]:
name = name.lower()
return qryd_gate_name_mapping.get(name, None) or Gate(name, 0, [])

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
return {(int(qubit.id),): None for qubit in qubits}
Expand Down
12 changes: 5 additions & 7 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
requests>=2.19
pydantic==1.9.2
qiskit-ibm-runtime==0.17.0
pydantic==2.5.0
qiskit-ibm-runtime==0.21.2
qiskit-ionq==0.5.0
qiskit-ibm-provider==0.7.2
dwave-ocean-sdk==6.4.1
qiskit-ibm-provider==0.10.0
dwave-ocean-sdk==6.9.0
qiskit-braket-provider==0.2.0
boto3==1.33.13
botocore==1.33.13
qiskit==0.44.1
qiskit==1.0.2
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name='planqk-quantum',
version="1.34.1",
version="2.0.0rc1",
author='Anaqor AG',
author_email='info@anaqor.io',
url='https://github.com/planqk/planqk-quantum',
Expand Down

0 comments on commit 7b7e328

Please sign in to comment.