Skip to content
Open
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
14 changes: 6 additions & 8 deletions mpqp/core/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1650,14 +1650,12 @@ def to_other_device(
if isinstance(device, (IBMDevice, StaticIBMSimulatedDevice)):
if job_type == JobType.STATE_VECTOR:
skip_measurements = True

if any(
isinstance(i, tuple(device.incompatible_gate()))
for i in self.instructions
):
raise ValueError(
f"Gate(s) {', '.join(map(str, device.incompatible_gate()))} cannot be simulated on {device}."
)
gate_set = list(device.compatible_gate())
Comment thread
hJaffaliColibritd marked this conversation as resolved.
if len(gate_set) != 0:
if any(type(i) not in gate_set for i in self.gates):
raise ValueError(
f"Gate(s) {', '.join(map(str, device.compatible_gate()))} cannot be simulated on {device}."
)
if (
isinstance(device, StaticIBMSimulatedDevice)
and device.value().num_qubits < self.nb_qubits
Expand Down
76 changes: 50 additions & 26 deletions mpqp/execution/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
from enum import Enum, auto

from mpqp.core.instruction.gates import Gate
from mpqp.core.instruction.gates.native_gates import *
from mpqp.environment.env_manager import get_env_variable
import warnings


class AvailableDevice(Enum):
Expand Down Expand Up @@ -90,7 +92,13 @@ def supports_observable(self) -> bool:
def supports_observable_ideal(self) -> bool:
pass

def incompatible_gate(self) -> set[type[Gate]]:
def compatible_gate(self, native_set: bool = False) -> set[type[Gate]]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that each time we add a gate to MPQP (which is not that often I admit) we have to remember to update each time all the compatible gates ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because more often than not we're going to transpile the circuit so we won't have forbidden gates by themselves.
For the cases that it's really needed we can do a list product with the NATIVE_GATES constant.

"""Returns the set of gates supported by the devices.

Args:
native_set: If True returns the set of gates of the device without any transpilation.
(For example: optimization_level=0 on Qiskit or Verbatim box on Braket)
"""
return set()


Expand All @@ -111,29 +119,23 @@ class IBMDevice(AvailableDevice):
AER_SIMULATOR_EXTENDED_STABILIZER = "extended_stabilizer"
AER_SIMULATOR_MATRIX_PRODUCT_STATE = "matrix_product_state"

IBM_SHERBROOKE = "ibm_sherbrooke"
IBM_BRISBANE = "ibm_brisbane"
IBM_KYIV = "ibm_kyiv"

IBM_FEZ = "ibm_fez"
IBM_RENSSELAER = "ibm_rensselaer"
IBM_BRUSSELS = "ibm_brussels"
IBM_KAWASAKI = "ibm_kawasaki"
IBM_QUEBEC = "ibm_quebec"
IBM_TORINO = "ibm_torino"
IBM_NAZCA = "ibm_nazca"
IBM_STRASBOURG = "ibm_strasbourg"

# RETIRED - IBM_OSAKA = "ibm_osaka"
# RETIRED - IBM_KYOTO = "ibm_kyoto"
# RETIRED - IBM_CUSCO = "ibm_cusco"
# RETIRED - IBM_ITHACA = "ibm_ithaca"

# NightHawk chips
IBM_BOSTON = "ibm_boston"
IBM_KINGSTON = "ibm_kingston"
IBM_PITTSBURGH = "ibm_pittsburgh"
IBM_FEZ = "ibm_fez"
IBM_MARRAKESH = "ibm_marrakesh"
IBM_AACHEN = "IBM_AACHEN"

# Heron chips
IBM_MIAMI = "ibm_miami"
IBM_BERLIN = "ibm_berlin"

IBM_CLEVELAND = "ibm_cleveland"
# RETIRED - IBM_CAIRO = "ibm_cairo"
# RETIRED - IBM_HANOI = "ibm_hanoi"
# RETIRED - IBM_ALGIERS = "ibm_algiers"
# RETIRED - IBM_KOLKATA = "ibm_kolkata"
# RETIRED - IBM_MUMBAI = "ibm_mumbai"
IBM_PEEKSKILL = "ibm_peekskill"

IBM_LEAST_BUSY = "ibm_least_busy"
Expand Down Expand Up @@ -184,17 +186,28 @@ def supports_observable_ideal(self) -> bool:
IBMDevice.AER_SIMULATOR_STATEVECTOR,
IBMDevice.AER_SIMULATOR_DENSITY_MATRIX,
IBMDevice.AER_SIMULATOR_STABILIZER,
# IBMDevice.AER_SIMULATOR_EXTENDED_STABILIZER,
IBMDevice.AER_SIMULATOR_MATRIX_PRODUCT_STATE,
}

def incompatible_gate(self) -> set[type[Gate]]:
from mpqp.core.instruction.gates import TOF, CRk, P, Rk, Rx, Ry, Rz, T, U

def compatible_gate(self, native_set: bool = False) -> set[type[Gate]]:
if self == IBMDevice.AER_SIMULATOR_STABILIZER:
return {CRk, P, Rk, Rx, Ry, Rz, T, TOF, U}
warnings.warn(
UserWarning(
f"For {self} the gates Rx, Ry and Rz are allowed but only at angles 0, π, π/2 and 3*π/2"
)
)
return {Rx, Ry, Rz, X, Y, Z, H, CNOT, CZ, S, S_dagger, SWAP}
elif self == IBMDevice.AER_SIMULATOR_EXTENDED_STABILIZER:
return {Rx, Rz}
warnings.warn(
UserWarning(
f"For {self} the gates Rx, Ry and Rz are allowed but only at angles 0, π, π/2 and 3*π/2"
)
)
return {Rx, Ry, Rz, X, Y, Z, H, CNOT, CZ, S, S_dagger, SWAP}
elif self in IBM_CHIPS_HERON:
return {CZ, Id, Rx, Rz, X} # add Rzz
elif self in IBM_CHIPS_NIGHTHAWK:
return {CZ, Id, Rx, Rz, X}
else:
return set()

Expand Down Expand Up @@ -512,3 +525,14 @@ def supports_observable(self) -> bool:

def supports_observable_ideal(self) -> bool:
return False


IBM_CHIPS_HERON = [IBMDevice.IBM_MIAMI, IBMDevice.IBM_BERLIN]
IBM_CHIPS_NIGHTHAWK = [
IBMDevice.IBM_BOSTON,
IBMDevice.IBM_KINGSTON,
IBMDevice.IBM_PITTSBURGH,
IBMDevice.IBM_FEZ,
IBMDevice.IBM_MARRAKESH,
IBMDevice.IBM_AACHEN,
]
Comment on lines +530 to +538
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit original to do it like this compared to the rest of devices?
Maybe a method to return that?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have a method but chips family like is more often done by IBM.
It felt bad adding a whole method for AvailableDevice only for an edge case of qiskit.

Copy link
Copy Markdown
Contributor

@hJaffaliColibritd hJaffaliColibritd May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to avoid instantiating a list the first time we import the file, but here it is not that a big deal

13 changes: 13 additions & 0 deletions mpqp/execution/simulated_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ def get_ibm_fake_providers() -> list[tuple[str, type["FakeBackendV2"]]]:
else:
return []

def is_retired(self) -> bool:
"""Function used to tell if the simulated device is retired or not.
Note: It only compare its name to a currently existing one, if an old simulated device has the same name as a new one it may break.
"""
from mpqp.execution.devices import IBMDevice

name = self.name[4:]
if name[-2:] == "V2":
name = name[:-2]
name = name.upper()
devices_names = IBMDevice._member_names_
return not any(name in device for device in devices_names)


class _LazyIBMSimulatedDevice:
_instance: Optional[type[StaticIBMSimulatedDevice]] = None
Expand Down
Loading