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

Commit

Permalink
fix: AWS simulator transpilation not using correct gateset
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Wagner committed Mar 21, 2024
1 parent 4d55d86 commit b57d42b
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 31 deletions.
5 changes: 3 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ dependencies:
- requests
# aws braket
# 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
#- git+https://github.com/qiskit-community/qiskit-braket-provider.git@main
- qiskit-braket-provider==0.2.0
# azure quantum
- azure-quantum[qiskit]==0.28.*
- qiskit-ionq==0.4.4
- qiskit-ionq==0.5.0
# dwave
- dwave-ocean-sdk==6.4.1
9 changes: 5 additions & 4 deletions planqk/qiskit/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from qiskit.providers.models import QasmBackendConfiguration, GateConfig
from qiskit.transpiler import Target

from planqk.qiskit.providers.job_input_converter import convert_to_backend_input, convert_to_backend_params
from .client.backend_dtos import ConfigurationDto, TYPE, BackendDto, ConnectivityDto, PROVIDER, HARDWARE_PROVIDER
from .client.job_dtos import JobDto
from .job import PlanqkJob
Expand Down Expand Up @@ -80,14 +79,14 @@ def _planqk_backend_to_target(self) -> Target:
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)
gate = adapter.op_to_instruction(name, is_simulator)

if gate is None:
continue

if gate.num_qubits == 1:
target.add_instruction(gate, single_qubit_props)
elif gate.num_qubits == 2:
elif gate.num_qubits > 1:
target.add_instruction(gate, multi_qubit_props)
elif gate.num_qubits == 0 and single_qubit_props == {None: None}:
# For gates without qubit number qargs can not be determined
Expand Down Expand Up @@ -168,6 +167,8 @@ def run(self, circuit, **kwargs) -> PlanqkJob:
Returns:
PlanqkJob: The job instance for the circuit that was run.
"""
from planqk.qiskit.providers.job_input_converter import convert_to_backend_input, convert_to_backend_params

self._validate_provider_for_backend()

if isinstance(circuit, (list, tuple)):
Expand All @@ -187,7 +188,7 @@ def run(self, circuit, **kwargs) -> PlanqkJob:
options[field] = kwargs[field]

supported_input_formats = self._backend_info.configuration.supported_input_formats
backend_input = convert_to_backend_input(supported_input_formats, circuit, options)
backend_input = convert_to_backend_input(supported_input_formats, circuit, self, options)
input_params = convert_to_backend_params(self._backend_info.provider, circuit, options)

job_request = JobDto(backend_id=self._backend_info.id,
Expand Down
2 changes: 1 addition & 1 deletion planqk/qiskit/providers/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class ProviderAdapter:
def op_to_instruction(self, operation: str) -> Optional[QiskitInstruction]:
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
pass

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
Expand Down
14 changes: 11 additions & 3 deletions planqk/qiskit/providers/aws/aws_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ def __init__(self, **kwargs):

@classmethod
def _default_options(cls):
return OptionsV2(
verbatim=False
)
return OptionsV2()


class PlanqkAwsSv1Backend(PlanqkAwsBackend):

def __init__(self, **kwargs):
super().__init__(**kwargs)

@classmethod
def _default_options(cls):
return OptionsV2()
16 changes: 10 additions & 6 deletions planqk/qiskit/providers/aws_adapter.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
from typing import Optional, List

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

import planqk.qiskit.providers.adapter as adapter
from planqk.qiskit.client.backend_dtos import QubitDto, ConnectivityDto
from planqk.qiskit.providers.aws_converters import qiskit_gate_name_to_braket_gate_mapping


class AwsAdapter(adapter.ProviderAdapter):
"""Adapter for AWS Braket backend."""

def op_to_instruction(self, operation: str) -> Optional[QiskitInstruction]:
def op_to_instruction(self, operation: str, is_simulator: bool = False) -> Optional[QiskitInstruction]:
operation = operation.lower()
gate = qiskit_gate_name_to_braket_gate_mapping.get(operation, None) or Gate(operation, 0, [])
# Braket only supports 1 and 2 qubit gates
return gate if gate.num_qubits < 3 else None
gate = _GATE_NAME_TO_QISKIT_GATE.get(operation, 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

def single_qubit_gate_props(self, qubits: List[QubitDto], is_simulator: bool = False):
if is_simulator:
return {None: None}
return {(int(qubit.id),): None for qubit in qubits}

def multi_qubit_gate_props(self, qubits: List[QubitDto], connectivity: ConnectivityDto, is_simulator: bool = False):
if is_simulator:
return {None: None}
if connectivity.fully_connected:
return {(int(qubit1.id), int(qubit2.id)): None for qubit1 in qubits for qubit2 in qubits
if qubit1.id != qubit2.id}
Expand Down
2 changes: 1 addition & 1 deletion planqk/qiskit/providers/azure_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


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

Expand Down
2 changes: 1 addition & 1 deletion planqk/qiskit/providers/ibm/ibm_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


class IbmAdapter(ProviderAdapter):
def op_to_instruction(self, operation: str) -> Optional[QiskitInstruction]:
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, [])

Expand Down
24 changes: 14 additions & 10 deletions planqk/qiskit/providers/job_input_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@

from braket.circuits import Circuit
from braket.circuits.circuit_helpers import validate_circuit_and_shots
from planqk.qiskit.client.backend_dtos import PROVIDER
from planqk.qiskit.client.job_dtos import INPUT_FORMAT
from planqk.qiskit.providers.aws_converters import transform_to_qasm_3_program
from planqk.qiskit.providers.qryd.qryd_converters import convert_to_wire_format, create_qoqu_input_params
from qiskit import QuantumCircuit
from qiskit.providers import Options
from qiskit_braket_provider.providers.adapter import to_braket
from qiskit_ibm_runtime import RuntimeEncoder
from qiskit_ionq.helpers import qiskit_circ_to_ionq_circ

from planqk.qiskit.backend import PlanqkBackend
from planqk.qiskit.client.backend_dtos import PROVIDER
from planqk.qiskit.client.job_dtos import INPUT_FORMAT
from planqk.qiskit.providers.aws_converters import transform_to_qasm_3_program
from planqk.qiskit.providers.qryd.qryd_converters import convert_to_wire_format, create_qoqu_input_params


def _convert_to_open_qasm_3(circuit: QuantumCircuit, options: Options):
def _convert_to_open_qasm_3(circuit: QuantumCircuit, backend: PlanqkBackend, options: Options):
shots = options.get("shots", 1)
inputs = options.get("inputs", {})
verbatim = options.get("verbatim", False)

braket_circuit = to_braket(circuit, verbatim=verbatim)
basis_gates = backend.operation_names if not verbatim else None
braket_circuit = to_braket(circuit, basis_gates, verbatim=verbatim)

validate_circuit_and_shots(braket_circuit, shots)

return transform_to_qasm_3_program(braket_circuit, False, inputs)
Expand All @@ -35,14 +39,14 @@ def _convert_to_ionq(circuit: QuantumCircuit, options: Options):
}


def _convert_to_qiskit_primitive(circuit: QuantumCircuit, options: Options):
def _convert_to_qiskit_primitive(circuit: QuantumCircuit, backend: PlanqkBackend, options: Options):
# Transforms circuit to base64 encoded byte stream
input_json_str = json.dumps(circuit, cls=RuntimeEncoder)
# Transform back to json but with the base64 encoded byte stream
return json.loads(input_json_str)


def _convert_to_qoqo_circuit(circuit: QuantumCircuit, options: Options):
def _convert_to_qoqo_circuit(circuit: QuantumCircuit, backend: PlanqkBackend, options: Options):
return convert_to_wire_format(circuit=circuit, options=options)


Expand Down Expand Up @@ -75,12 +79,12 @@ class UnsupportedFormatException(Exception):
pass


def convert_to_backend_input(supported_input_formats: List[INPUT_FORMAT], circuit, options=None) \
def convert_to_backend_input(supported_input_formats: List[INPUT_FORMAT], circuit, backend, options=None) \
-> Tuple[INPUT_FORMAT, dict]:
for input_format in supported_input_formats:
convert_circuit = input_format_converter_factory.get(input_format)
if convert_circuit:
return input_format, convert_circuit(circuit=circuit, options=options)
return input_format, convert_circuit(circuit=circuit, backend=backend, options=options)
raise UnsupportedFormatException("Could not convert input to any of the supported inputs formats of the actual")


Expand Down
2 changes: 1 addition & 1 deletion planqk/qiskit/providers/qryd/qryd_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@


class QrydAdapter(adapter.ProviderAdapter):
def op_to_instruction(self, operation: str) -> Optional[QiskitInstruction]:
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, [])

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
requests>=2.19
pydantic==1.9.2
qiskit-ibm-runtime==0.17.0
qiskit-ionq==0.4.7
qiskit-ionq==0.5.0
qiskit-ibm-provider==0.7.2
dwave-ocean-sdk==6.4.1
qiskit-braket-provider==0.1.1
qiskit-braket-provider==0.2.0
boto3==1.33.13
botocore==1.33.13
qiskit==0.44.1

0 comments on commit b57d42b

Please sign in to comment.