From b698648deb4112197e7e49f5ecd2cfc4f2cfc618 Mon Sep 17 00:00:00 2001 From: Nagji Date: Mon, 29 Jul 2024 16:25:11 -0700 Subject: [PATCH] change: Use 'validator' in place of 'criterion', fix usage of generic program type in EmulatorPasses --- src/braket/aws/aws_device.py | 30 ++++---- src/braket/aws/aws_emulator_helpers.py | 76 +++++++++---------- src/braket/emulation/__init__.py | 1 + .../base_emulator.py} | 35 ++++----- .../{emulators => emulation}/emulator.py | 24 +++--- .../emulation/emulator_passes/__init__.py | 8 ++ .../emulator_passes/criteria/__init__.py | 11 +++ .../criteria/connectivity_validator.py} | 37 ++++----- .../criteria/gate_connectivity_validator.py} | 32 ++++---- .../criteria/gate_validator.py} | 48 +++++++----- .../criteria/qubit_count_validator.py} | 14 ++-- .../criteria/validation_pass.py} | 22 +----- .../emulator_passes/emulator_pass.py | 4 +- src/braket/emulators/__init__.py | 1 - .../emulators/emulator_passes/__init__.py | 8 -- .../emulator_passes/criteria/__init__.py | 13 ---- .../braket/aws/test_aws_emulation.py | 38 +++++----- ...rion.py => test_connectivity_validator.py} | 44 +++++------ .../braket/emulation/test_emulator.py | 56 +++++++------- ...py => test_gate_connectivity_validator.py} | 50 ++++++------ ...te_criterion.py => test_gate_validator.py} | 32 ++++---- ...erion.py => test_qubit_count_validator.py} | 16 ++-- 22 files changed, 295 insertions(+), 305 deletions(-) create mode 100644 src/braket/emulation/__init__.py rename src/braket/{emulators/emulator_interface.py => emulation/base_emulator.py} (61%) rename src/braket/{emulators => emulation}/emulator.py (90%) create mode 100644 src/braket/emulation/emulator_passes/__init__.py create mode 100644 src/braket/emulation/emulator_passes/criteria/__init__.py rename src/braket/{emulators/emulator_passes/criteria/connectivity_criterion.py => emulation/emulator_passes/criteria/connectivity_validator.py} (85%) rename src/braket/{emulators/emulator_passes/criteria/gate_connectivity_criterion.py => emulation/emulator_passes/criteria/gate_connectivity_validator.py} (84%) rename src/braket/{emulators/emulator_passes/criteria/gate_criterion.py => emulation/emulator_passes/criteria/gate_validator.py} (63%) rename src/braket/{emulators/emulator_passes/criteria/qubit_count_criterion.py => emulation/emulator_passes/criteria/qubit_count_validator.py} (68%) rename src/braket/{emulators/emulator_passes/criteria/emulator_criterion.py => emulation/emulator_passes/criteria/validation_pass.py} (56%) rename src/braket/{emulators => emulation}/emulator_passes/emulator_pass.py (88%) delete mode 100644 src/braket/emulators/__init__.py delete mode 100644 src/braket/emulators/emulator_passes/__init__.py delete mode 100644 src/braket/emulators/emulator_passes/criteria/__init__.py rename test/unit_tests/braket/emulation/{test_connectivity_criterion.py => test_connectivity_validator.py} (80%) rename test/unit_tests/braket/emulation/{test_gate_connectivity_criterion.py => test_gate_connectivity_validator.py} (85%) rename test/unit_tests/braket/emulation/{test_gate_criterion.py => test_gate_validator.py} (82%) rename test/unit_tests/braket/emulation/{test_qubit_count_criterion.py => test_qubit_count_validator.py} (74%) diff --git a/src/braket/aws/aws_device.py b/src/braket/aws/aws_device.py index 530c67186..f9a9463c0 100644 --- a/src/braket/aws/aws_device.py +++ b/src/braket/aws/aws_device.py @@ -28,10 +28,10 @@ from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation from braket.annealing.problem import Problem from braket.aws.aws_emulator_helpers import ( - connectivity_criterion, - gate_connectivity_criterion, - gate_criterion, - qubit_count_criterion, + connectivity_validator, + gate_connectivity_validator, + gate_validator, + qubit_count_validator, ) from braket.aws.aws_noise_models import device_noise_model from braket.aws.aws_quantum_task import AwsQuantumTask @@ -48,8 +48,8 @@ from braket.device_schema.pulse.pulse_device_action_properties_v1 import PulseDeviceActionProperties from braket.devices import Devices from braket.devices.device import Device -from braket.emulators import Emulator -from braket.emulators.emulator_passes import ProgramType +from braket.emulation import Emulator +from braket.emulation.emulator_passes import ProgramType from braket.ir.blackbird import Program as BlackbirdProgram from braket.ir.openqasm import Program as OpenQasmProgram from braket.parametric.free_parameter import FreeParameter @@ -908,15 +908,15 @@ def _setup_emulator(self) -> Emulator: noise_model=emulator_noise_model, backend="braket_dm", name=self._name ) - self._emulator.add_pass(qubit_count_criterion(self.properties)) - self._emulator.add_pass(gate_criterion(self.properties)) - self._emulator.add_pass(connectivity_criterion(self.properties, self.topology_graph)) - self._emulator.add_pass(gate_connectivity_criterion(self.properties, self.topology_graph)) + self._emulator.add_pass(qubit_count_validator(self.properties)) + self._emulator.add_pass(gate_validator(self.properties)) + self._emulator.add_pass(connectivity_validator(self.properties, self.topology_graph)) + self._emulator.add_pass(gate_connectivity_validator(self.properties, self.topology_graph)) return self._emulator def validate( self, - task_specification: Circuit, + task_specification: ProgramType, ) -> None: """ Runs all non-modifying emulator passes on the input program and raises an @@ -924,14 +924,14 @@ def validate( program meets all criteria, returns. Args: - task_specification (Circuit): The quantum program to emulate against + task_specification (ProgramType): The quantum program to emulate against this AwsDevice device properties. """ self.emulator.validate(task_specification) return - def run_emulator_passes( + def run_passes( self, task_specification: ProgramType, apply_noise_model: bool = True ) -> ProgramType: """ @@ -954,7 +954,7 @@ def run_emulator_passes( def emulate( self, - task_specification: Circuit, + task_specification: ProgramType, shots: Optional[int] = None, inputs: Optional[dict[str, float]] = None, ) -> QuantumTask: @@ -964,7 +964,7 @@ def emulate( the program on the emulator's backend. Args: - task_specification (Circuit): Specification of a quantum task + task_specification (ProgramType): Specification of a quantum task to run on device. shots (Optional[int]): The number of times to run the quantum task on the device. diff --git a/src/braket/aws/aws_emulator_helpers.py b/src/braket/aws/aws_emulator_helpers.py index 719c6bd34..f054dee61 100644 --- a/src/braket/aws/aws_emulator_helpers.py +++ b/src/braket/aws/aws_emulator_helpers.py @@ -8,17 +8,17 @@ from braket.device_schema.ionq import IonqDeviceCapabilities from braket.device_schema.iqm import IqmDeviceCapabilities from braket.device_schema.rigetti import RigettiDeviceCapabilities -from braket.emulators.emulator_passes import ( - ConnectivityCriterion, - GateConnectivityCriterion, - GateCriterion, - QubitCountCriterion, +from braket.emulation.emulator_passes import ( + ConnectivityValidator, + GateConnectivityValidator, + GateValidator, + QubitCountValidator, ) -def qubit_count_criterion(properties: DeviceCapabilities) -> QubitCountCriterion: +def qubit_count_validator(properties: DeviceCapabilities) -> QubitCountValidator: """ - Create a QubitCountCriterion pass which checks that the number of qubits used in a program does + Create a QubitCountValidator pass which checks that the number of qubits used in a program does not exceed the number of qubits allowed by a QPU, as defined in the device properties. Args: @@ -26,16 +26,16 @@ def qubit_count_criterion(properties: DeviceCapabilities) -> QubitCountCriterion QHP-specific schema. Returns: - QubitCountCriterion: An emulator pass that checks that the number of qubits used in a + QubitCountValidator: An emulator pass that checks that the number of qubits used in a program does not exceed that of the max qubit count on the device. """ qubit_count = properties.paradigm.qubitCount - return QubitCountCriterion(qubit_count) + return QubitCountValidator(qubit_count) -def gate_criterion(properties: DeviceCapabilities) -> GateCriterion: +def gate_validator(properties: DeviceCapabilities) -> GateValidator: """ - Create a GateCriterion pass which defines what supported and native gates are allowed in a + Create a GateValidator pass which defines what supported and native gates are allowed in a program based on the provided device properties. Args: @@ -43,21 +43,21 @@ def gate_criterion(properties: DeviceCapabilities) -> GateCriterion: QHP-specific schema. Returns: - GateCriterion: An emulator pass that checks that a circuit only uses supported gates and + GateValidator: An emulator pass that checks that a circuit only uses supported gates and verbatim circuits only use native gates. """ supported_gates = properties.action[DeviceActionType.OPENQASM].supportedOperations native_gates = properties.paradigm.nativeGateSet - return GateCriterion(supported_gates=supported_gates, native_gates=native_gates) + return GateValidator(supported_gates=supported_gates, native_gates=native_gates) -def connectivity_criterion( +def connectivity_validator( properties: DeviceCapabilities, connectivity_graph: DiGraph -) -> ConnectivityCriterion: +) -> ConnectivityValidator: """ - Creates a ConnectivityCriterion pass which validates that two-qubit gates are applied to + Creates a ConnectivityValidator pass which validates that two-qubit gates are applied to connected qubits based on this device's connectivity graph. Args: @@ -67,53 +67,53 @@ def connectivity_criterion( connectivity_graph (DiGraph): Connectivity graph for this device. Returns: - ConnectivityCriterion: An emulator pass that checks that a circuit only applies two-qubit + ConnectivityValidator: An emulator pass that checks that a circuit only applies two-qubit gates to connected qubits on the device. """ - return _connectivity_criterion(properties, connectivity_graph) + return _connectivity_validator(properties, connectivity_graph) @singledispatch -def _connectivity_criterion( +def _connectivity_validator( properties: DeviceCapabilities, connectivity_graph: DiGraph -) -> ConnectivityCriterion: +) -> ConnectivityValidator: - connectivity_criterion = ConnectivityCriterion(connectivity_graph) - return connectivity_criterion + connectivity_validator = ConnectivityValidator(connectivity_graph) + return connectivity_validator -@_connectivity_criterion.register(IqmDeviceCapabilities) -def _(properties: IqmDeviceCapabilities, connectivity_graph: DiGraph) -> ConnectivityCriterion: +@_connectivity_validator.register(IqmDeviceCapabilities) +def _(properties: IqmDeviceCapabilities, connectivity_graph: DiGraph) -> ConnectivityValidator: """ IQM qubit connectivity is undirected but the directed graph that represents qubit connectivity does not include back-edges. Thus, we must explicitly introduce back edges before creating - the ConnectivityCriterion for an IQM device. + the ConnectivityValidator for an IQM device. """ connectivity_graph = connectivity_graph.copy() for edge in connectivity_graph.edges: connectivity_graph.add_edge(edge[1], edge[0]) - return ConnectivityCriterion(connectivity_graph) + return ConnectivityValidator(connectivity_graph) -def gate_connectivity_criterion( +def gate_connectivity_validator( properties: DeviceCapabilities, connectivity_graph: DiGraph -) -> GateConnectivityCriterion: - return _gate_connectivity_criterion(properties, connectivity_graph) +) -> GateConnectivityValidator: + return _gate_connectivity_validator(properties, connectivity_graph) @singledispatch -def _gate_connectivity_criterion( +def _gate_connectivity_validator( properties: DeviceCapabilities, connectivity_graph: DiGraph -) -> GateConnectivityCriterion: +) -> GateConnectivityValidator: raise NotImplementedError -@_gate_connectivity_criterion.register(IqmDeviceCapabilities) -@_gate_connectivity_criterion.register(RigettiDeviceCapabilities) +@_gate_connectivity_validator.register(IqmDeviceCapabilities) +@_gate_connectivity_validator.register(RigettiDeviceCapabilities) def _( properties: RigettiDeviceCapabilities, connectivity_graph: DiGraph -) -> GateConnectivityCriterion: +) -> GateConnectivityValidator: """ Both IQM and Rigetti have undirected connectivity graphs; Rigetti device capabilities provide back edges, but the calibration data only provides edges in one direction. @@ -145,11 +145,11 @@ def _( v, u, supported_gates=set(gate_connectivity_graph[u][v]["supported_gates"]) ) - return GateConnectivityCriterion(gate_connectivity_graph) + return GateConnectivityValidator(gate_connectivity_graph) -@_gate_connectivity_criterion.register(IonqDeviceCapabilities) -def _(properties: IonqDeviceCapabilities, connectivity_graph: DiGraph) -> GateConnectivityCriterion: +@_gate_connectivity_validator.register(IonqDeviceCapabilities) +def _(properties: IonqDeviceCapabilities, connectivity_graph: DiGraph) -> GateConnectivityValidator: """ Qubits in IonQ's trapped ion devices are all fully connected with identical gate-pair capabilities. IonQ does not expliclty provide a set of edges for @@ -162,7 +162,7 @@ def _(properties: IonqDeviceCapabilities, connectivity_graph: DiGraph) -> GateCo for edge in gate_connectivity_graph.edges: gate_connectivity_graph[edge[0]][edge[1]]["supported_gates"] = set(native_gates) - return GateConnectivityCriterion(gate_connectivity_graph) + return GateConnectivityValidator(gate_connectivity_graph) def _get_qpu_gate_translations( diff --git a/src/braket/emulation/__init__.py b/src/braket/emulation/__init__.py new file mode 100644 index 000000000..e1c29ccd4 --- /dev/null +++ b/src/braket/emulation/__init__.py @@ -0,0 +1 @@ +from braket.emulation.emulator import Emulator # noqa: F40 diff --git a/src/braket/emulators/emulator_interface.py b/src/braket/emulation/base_emulator.py similarity index 61% rename from src/braket/emulators/emulator_interface.py rename to src/braket/emulation/base_emulator.py index 8c5d7cadc..63bcb3c11 100644 --- a/src/braket/emulators/emulator_interface.py +++ b/src/braket/emulation/base_emulator.py @@ -1,19 +1,18 @@ from __future__ import annotations -from abc import ABC from typing import Iterable, Union -from braket.emulators.emulator_passes import EmulatorPass, ProgramType -from braket.emulators.emulator_passes.criteria import EmulatorCriterion +from braket.emulation.emulator_passes import EmulationPass, ProgramType +from braket.emulation.emulator_passes.criteria import ValidationPass -class EmulatorInterface(ABC): - def __init__(self, emulator_passes: Iterable[EmulatorPass] = None): +class BaseEmulator: + def __init__(self, emulator_passes: Iterable[EmulationPass] = None): self._emulator_passes = emulator_passes if emulator_passes is not None else [] def run_passes(self, task_specification: ProgramType) -> ProgramType: """ - This method passes the input program through the EmulatorPasses contained + This method passes the input program through the EmulationPasses contained within this emulator. An emulator pass may simply validate a program or may modify or entirely transform the program (to an equivalent quantum program). @@ -30,7 +29,7 @@ def run_passes(self, task_specification: ProgramType) -> ProgramType: def validate(self, task_specification: ProgramType) -> None: """ - This method passes the input program through EmulatorPasses that perform + This method passes the input program through EmulationPasses that perform only validation, without modifying the input program. Args: @@ -38,32 +37,34 @@ def validate(self, task_specification: ProgramType) -> None: emulator's validation passes. """ for emulator_pass in self._emulator_passes: - if isinstance(emulator_pass, EmulatorCriterion): + if isinstance(emulator_pass, ValidationPass): emulator_pass(task_specification) def add_pass( - self, emulator_pass: Union[Iterable[EmulatorPass], EmulatorPass] - ) -> EmulatorInterface: + self, emulator_pass: Union[Iterable[EmulationPass], EmulationPass] + ) -> BaseEmulator: """ - Append a new EmulatorPass or a list of EmulatorPass objects. + Append a new EmulationPass or a list of EmulationPass objects. Args: - emulator_pass (Union[Iterable[EmulatorPass], EmulatorPass]): Either a - single EmulatorPass object or a list of EmulatorPass objects that + emulator_pass (Union[Iterable[EmulationPass], EmulationPass]): Either a + single EmulationPass object or a list of EmulationPass objects that will be used in validation and program compilation passes by this emulator. Returns: - EmulatorInterface: Returns an updated self. + BaseEmulator: Returns an updated self. Raises: - TypeError: If the input is not an iterable or an EmulatorPass. + TypeError: If the input is not an iterable or an EmulationPass. """ if isinstance(emulator_pass, Iterable): self._emulator_passes.extend(emulator_pass) - elif isinstance(emulator_pass, EmulatorPass): + elif isinstance(emulator_pass, EmulationPass): self._emulator_passes.append(emulator_pass) else: - raise TypeError("emulator_pass must be an EmulatorPass or an iterable of EmulatorPass") + raise TypeError( + "emulator_pass must be an EmulationPass or an iterable of EmulationPass" + ) return self diff --git a/src/braket/emulators/emulator.py b/src/braket/emulation/emulator.py similarity index 90% rename from src/braket/emulators/emulator.py rename to src/braket/emulation/emulator.py index cfea4a55f..ec20563d4 100644 --- a/src/braket/emulators/emulator.py +++ b/src/braket/emulation/emulator.py @@ -7,17 +7,17 @@ from braket.circuits.noise_model import NoiseModel from braket.devices import Device from braket.devices.local_simulator import LocalSimulator -from braket.emulators.emulator_interface import EmulatorInterface -from braket.emulators.emulator_passes import EmulatorPass, ProgramType +from braket.emulation.base_emulator import BaseEmulator +from braket.emulation.emulator_passes import EmulationPass, ProgramType from braket.ir.openqasm import Program as OpenQasmProgram from braket.tasks import QuantumTask from braket.tasks.quantum_task_batch import QuantumTaskBatch -class Emulator(Device, EmulatorInterface): +class Emulator(Device, BaseEmulator): - DEFAULT_SIMULATOR_BACKEND = "default" - DEFAULT_NOISY_BACKEND = "braket_dm" + _DEFAULT_SIMULATOR_BACKEND = "default" + _DEFAULT_NOISY_BACKEND = "braket_dm" """An emulator is a simulation device that more closely resembles the capabilities and constraints of a real device or of a specific device model.""" @@ -26,11 +26,11 @@ def __init__( self, backend: str = "default", noise_model: Optional[NoiseModel] = None, - emulator_passes: Iterable[EmulatorPass] = None, + emulator_passes: Iterable[EmulationPass] = None, **kwargs, ): Device.__init__(self, name=kwargs.get("name", "DeviceEmulator"), status="AVAILABLE") - EmulatorInterface.__init__(self, emulator_passes) + BaseEmulator.__init__(self, emulator_passes) self._noise_model = noise_model backend_name = self._get_local_simulator_backend(backend, noise_model) @@ -57,8 +57,8 @@ def _get_local_simulator_backend( "Setting LocalSimulator backend to use 'braket_dm' \ because a NoiseModel was provided." ) - return Emulator.DEFAULT_NOISY_BACKEND - return Emulator.DEFAULT_SIMULATOR_BACKEND + return Emulator._DEFAULT_NOISY_BACKEND + return Emulator._DEFAULT_SIMULATOR_BACKEND def run( self, @@ -142,13 +142,13 @@ def run_passes( self, task_specification: ProgramType, apply_noise_model: bool = True ) -> ProgramType: """ - Passes the input program through all EmulatorPass objects contained in this + Passes the input program through all EmulationPass objects contained in this emulator and applies the emulator's noise model, if it exists, before returning the compiled program. Args: task_specification (ProgramType): The input program to validate and - compile based on this emulator's EmulatorPasses + compile based on this emulator's EmulationPasses apply_noise_model (bool): If true, apply this emulator's noise model to the compiled program before returning the final program. @@ -166,7 +166,7 @@ def run_passes( def validate(self, task_specification: ProgramType) -> None: """ - Runs only EmulatorPasses that are EmulatorCriterion, i.e. all non-modifying + Runs only EmulationPasses that are ValidationPass, i.e. all non-modifying validation passes on the input program. Args: diff --git a/src/braket/emulation/emulator_passes/__init__.py b/src/braket/emulation/emulator_passes/__init__.py new file mode 100644 index 000000000..0f328d6fa --- /dev/null +++ b/src/braket/emulation/emulator_passes/__init__.py @@ -0,0 +1,8 @@ +from braket.emulation.emulator_passes.criteria import ( # noqa: F401 + ConnectivityValidator, + GateConnectivityValidator, + GateValidator, + QubitCountValidator, + ValidationPass, +) +from braket.emulation.emulator_passes.emulator_pass import EmulationPass, ProgramType # noqa: F401 diff --git a/src/braket/emulation/emulator_passes/criteria/__init__.py b/src/braket/emulation/emulator_passes/criteria/__init__.py new file mode 100644 index 000000000..c15972293 --- /dev/null +++ b/src/braket/emulation/emulator_passes/criteria/__init__.py @@ -0,0 +1,11 @@ +from braket.emulation.emulator_passes.criteria.connectivity_validator import ( # noqa: F401 + ConnectivityValidator, +) +from braket.emulation.emulator_passes.criteria.gate_connectivity_validator import ( # noqa: F401 + GateConnectivityValidator, +) +from braket.emulation.emulator_passes.criteria.gate_validator import GateValidator # noqa: F401 +from braket.emulation.emulator_passes.criteria.qubit_count_validator import ( # noqa: F401 + QubitCountValidator, +) +from braket.emulation.emulator_passes.criteria.validation_pass import ValidationPass # noqa: F401 diff --git a/src/braket/emulators/emulator_passes/criteria/connectivity_criterion.py b/src/braket/emulation/emulator_passes/criteria/connectivity_validator.py similarity index 85% rename from src/braket/emulators/emulator_passes/criteria/connectivity_criterion.py rename to src/braket/emulation/emulator_passes/criteria/connectivity_validator.py index 3f3298b41..c3557cb31 100644 --- a/src/braket/emulators/emulator_passes/criteria/connectivity_criterion.py +++ b/src/braket/emulation/emulator_passes/criteria/connectivity_validator.py @@ -7,21 +7,21 @@ from braket.circuits import Circuit from braket.circuits.compiler_directives import StartVerbatimBox from braket.circuits.gate import Gate -from braket.emulators.emulator_passes.criteria.emulator_criterion import EmulatorCriterion +from braket.emulation.emulator_passes.criteria.validation_pass import ValidationPass from braket.registers.qubit_set import QubitSet -class ConnectivityCriterion(EmulatorCriterion): +class ConnectivityValidator(ValidationPass[Circuit]): def __init__( self, connectivity_graph: Optional[Union[Dict[int, Iterable[int]], DiGraph]] = None, - fully_connected=False, + fully_connected: bool = False, num_qubits: Optional[int] = None, qubit_labels: Optional[Union[Iterable[int], QubitSet]] = None, directed: bool = True, ): """ - A ConnectivityCriterion instance takes in a qubit connectivity graph and validates that + A ConnectivityValidator instance takes in a qubit connectivity graph and validates that a circuit that uses verbatim circuits makes valid hardware qubit references in single and two-qubit gate operations. @@ -50,9 +50,10 @@ def __init__( or a valid DiGraph or dict representation of a connectivity graph is not provided. """ - if not (connectivity_graph or fully_connected): + if not ((connectivity_graph is not None) ^ fully_connected): raise ValueError( - "Either the connectivity_graph must be provided or fully_connected must be True." + "Either the connectivity_graph must be provided OR fully_connected must be True\ + (not both)." ) if fully_connected: @@ -81,15 +82,15 @@ def __init__( for edge in self._connectivity_graph.edges: self._connectivity_graph.add_edge(edge[1], edge[0]) - def validate(self, circuit: Circuit) -> None: + def validate(self, program: Circuit) -> None: """ Verifies that any verbatim box in a circuit is runnable with respect to the - device connectivity definied by this criterion. If any sub-circuit of the + device connectivity definied by this validator. If any sub-circuit of the input circuit is verbatim, we validate the connectivity of all gate operations in the circuit. Args: - circuit (Circuit): The Braket circuit whose gate operations to + program (Circuit): The Braket circuit whose gate operations to validate. Raises: @@ -100,17 +101,17 @@ def validate(self, circuit: Circuit) -> None: if not any( [ isinstance(instruction.operator, StartVerbatimBox) - for instruction in circuit.instructions + for instruction in program.instructions ] ): return - for idx in range(len(circuit.instructions)): - instruction = circuit.instructions[idx] + for idx in range(len(program.instructions)): + instruction = program.instructions[idx] if isinstance(instruction.operator, Gate): if ( instruction.operator.qubit_count == 2 ): # Assuming only maximum 2-qubit native gates are supported - self.validate_instruction_connectivity(instruction.control, instruction.target) + self._validate_instruction_connectivity(instruction.control, instruction.target) else: # just check that the target qubit exists in the connectivity graph target_qubit = instruction.target[0] @@ -119,11 +120,11 @@ def validate(self, circuit: Circuit) -> None: f"Qubit {target_qubit} does not exist in the device topology." ) - def validate_instruction_connectivity( + def _validate_instruction_connectivity( self, control_qubits: QubitSet, target_qubits: QubitSet ) -> None: """ - Checks if a two-qubit instruction is valid based on this criterion's connectivity + Checks if a two-qubit instruction is valid based on this validator's connectivity graph. Args: @@ -148,12 +149,12 @@ def validate_instruction_connectivity( ) else: raise ValueError("Unrecognized qubit targetting setup for a 2 qubit gate.") - # Check that each edge exists in this criterion's connectivity graph + # Check that each edge exists in this validator's connectivity graph for e in gate_connectivity_graph.edges: if not self._connectivity_graph.has_edge(*e): raise ValueError(f"{e[0]} is not connected to qubit {e[1]} in this device.") - def __eq__(self, other: EmulatorCriterion) -> bool: - return isinstance(other, ConnectivityCriterion) and graphs_equal( + def __eq__(self, other: ValidationPass) -> bool: + return isinstance(other, ConnectivityValidator) and graphs_equal( self._connectivity_graph, other._connectivity_graph ) diff --git a/src/braket/emulators/emulator_passes/criteria/gate_connectivity_criterion.py b/src/braket/emulation/emulator_passes/criteria/gate_connectivity_validator.py similarity index 84% rename from src/braket/emulators/emulator_passes/criteria/gate_connectivity_criterion.py rename to src/braket/emulation/emulator_passes/criteria/gate_connectivity_validator.py index 9603a6c25..e78b11e25 100644 --- a/src/braket/emulators/emulator_passes/criteria/gate_connectivity_criterion.py +++ b/src/braket/emulation/emulator_passes/criteria/gate_connectivity_validator.py @@ -6,11 +6,11 @@ from braket.circuits.circuit import Circuit from braket.circuits.compiler_directives import EndVerbatimBox, StartVerbatimBox from braket.circuits.gate import Gate -from braket.emulators.emulator_passes.criteria.emulator_criterion import EmulatorCriterion +from braket.emulation.emulator_passes.criteria.validation_pass import ValidationPass from braket.registers.qubit_set import QubitSet -class GateConnectivityCriterion(EmulatorCriterion): +class GateConnectivityValidator(ValidationPass[Circuit]): def __init__( self, gate_connectivity_graph: Union[Dict[Tuple[Any, Any], Iterable[str]], DiGraph], @@ -54,32 +54,32 @@ def __init__( gate sets." ) - def validate(self, circuit: Circuit) -> None: + def validate(self, program: Circuit) -> None: """ Verifies that any multiqubit gates used within a verbatim box are supported by the devices gate connectivity defined by this criteria. Args: - circuit (Circuit): The circuit whose gate instructions need to be validated - against this criterion's gate connectivity graph. + program (Circuit): The circuit whose gate instructions need to be validated + against this validator's gate connectivity graph. Raises: ValueError if any of the gate operations use qubits or qubit edges that don't exist in the qubit connectivity graph or the gate operation is not supported by the edge. """ - for idx in range(len(circuit.instructions)): - instruction = circuit.instructions[idx] + for idx in range(len(program.instructions)): + instruction = program.instructions[idx] if isinstance(instruction.operator, StartVerbatimBox): idx += 1 - while idx < len(circuit.instructions) and not isinstance( - circuit.instructions[idx].operator, EndVerbatimBox + while idx < len(program.instructions) and not isinstance( + program.instructions[idx].operator, EndVerbatimBox ): - instruction = circuit.instructions[idx] + instruction = program.instructions[idx] if isinstance(instruction.operator, Gate): if ( instruction.operator.qubit_count == 2 ): # Assuming only maximum 2-qubit native gates are supported - self.validate_instruction_connectivity( + self._validate_instruction_connectivity( instruction.operator.name, instruction.control, instruction.target ) else: @@ -92,12 +92,12 @@ def validate(self, circuit: Circuit) -> None: idx += 1 idx += 1 - def validate_instruction_connectivity( + def _validate_instruction_connectivity( self, gate_name: str, control_qubits: QubitSet, target_qubits: QubitSet ) -> None: """ Checks if a specific is able to be applied to the control and target qubits based - on this criterion's gate connectivity graph. + on this validator's gate connectivity graph. Args: gate_name (str): The name of the gate being applied. @@ -115,7 +115,7 @@ def validate_instruction_connectivity( else: raise ValueError("Unrecognized qubit targetting setup for a 2 qubit gate.") - # Check that each edge exists in this criterion's connectivity graph + # Check that each edge exists in this validator's connectivity graph if not self._gate_connectivity_graph.has_edge(*e): raise ValueError(f"{e[0]} is not connected to {e[1]} on this device.") supported_gates = self._gate_connectivity_graph[e[0]][e[1]]["supported_gates"] @@ -124,7 +124,7 @@ def validate_instruction_connectivity( f"Qubit pair ({e[0]}, {e[1]}) does not support gate {gate_name} on this device." ) - def __eq__(self, other: EmulatorCriterion) -> bool: - return isinstance(other, GateConnectivityCriterion) and graphs_equal( + def __eq__(self, other: ValidationPass) -> bool: + return isinstance(other, GateConnectivityValidator) and graphs_equal( self._gate_connectivity_graph, other._gate_connectivity_graph ) diff --git a/src/braket/emulators/emulator_passes/criteria/gate_criterion.py b/src/braket/emulation/emulator_passes/criteria/gate_validator.py similarity index 63% rename from src/braket/emulators/emulator_passes/criteria/gate_criterion.py rename to src/braket/emulation/emulator_passes/criteria/gate_validator.py index 52d6072a2..f8c2c0f83 100644 --- a/src/braket/emulators/emulator_passes/criteria/gate_criterion.py +++ b/src/braket/emulation/emulator_passes/criteria/gate_validator.py @@ -1,25 +1,31 @@ from collections.abc import Iterator +from typing import Optional from braket.circuits import Circuit from braket.circuits.compiler_directives import EndVerbatimBox, StartVerbatimBox from braket.circuits.gate import Gate from braket.circuits.translations import BRAKET_GATES -from braket.emulators.emulator_passes.criteria.emulator_criterion import EmulatorCriterion +from braket.emulation.emulator_passes.criteria.validation_pass import ValidationPass -class GateCriterion(EmulatorCriterion): - def __init__(self, supported_gates: Iterator[str] = [], native_gates: Iterator[str] = []): +class GateValidator(ValidationPass[Circuit]): + def __init__( + self, + supported_gates: Optional[Iterator[str]] = None, + native_gates: Optional[Iterator[str]] = None, + ): """ Args: - supported_gates (Iterator[str]): A list of gates supported outside of verbatim mode - by the emulator. A gate is a Braket gate name. - native_gates (Iterator[str]): A list of gates supported inside of verbatim mode by - the emulator. + supported_gates (Optional[Iterator[str]]): A list of gates supported outside of + verbatim modeby the emulator. A gate is a Braket gate name. + native_gates (Optional[Iterator[str]]): A list of gates supported inside of + verbatim mode by the emulator. Raises: ValueError: If supported_gates and and native_gates are empty or any of the provided gate are not supported by the Braket BDK. """ + supported_gates, native_gates = (supported_gates or []), (native_gates or []) if not len(supported_gates) and not len(native_gates): raise ValueError("Supported gate set or native gate set must be provided.") @@ -33,28 +39,28 @@ def __init__(self, supported_gates: Iterator[str] = [], native_gates: Iterator[s except KeyError as e: raise ValueError(f"Input {str(e)} in native_gates is not a valid Braket gate name.") - def validate(self, circuit: Circuit) -> None: + def validate(self, program: Circuit) -> None: """ - Checks that all non-verbatim gates used in the circuit are in this criterion's + Checks that all non-verbatim gates used in the circuit are in this validator's supported gate set and that all verbatim gates used in the circuit are in this - criterion's native gate set. + validator's native gate set. Args: - circuit (Circuit): The Braket circuit whose gates to validate. + program (Circuit): The Braket circuit whose gates to validate. Raises: - ValueError: If a gate operation or verbatim gate operation is not in this criterion's + ValueError: If a gate operation or verbatim gate operation is not in this validator's supported or native gate set, respectively. """ idx = 0 - while idx < len(circuit.instructions): - instruction = circuit.instructions[idx] + while idx < len(program.instructions): + instruction = program.instructions[idx] if isinstance(instruction.operator, StartVerbatimBox): idx += 1 - while idx < len(circuit.instructions) and not isinstance( - circuit.instructions[idx].operator, EndVerbatimBox + while idx < len(program.instructions) and not isinstance( + program.instructions[idx].operator, EndVerbatimBox ): - instruction = circuit.instructions[idx] + instruction = program.instructions[idx] if isinstance(instruction.operator, Gate): gate = instruction.operator if not type(gate) in self._native_gates: @@ -62,8 +68,8 @@ def validate(self, circuit: Circuit) -> None: f"Gate {gate.name} is not a native gate supported by this device." ) idx += 1 - if idx == len(circuit.instructions) or not isinstance( - circuit.instructions[idx].operator, EndVerbatimBox + if idx == len(program.instructions) or not isinstance( + program.instructions[idx].operator, EndVerbatimBox ): raise ValueError(f"No end verbatim box found at index {idx} in the circuit.") elif isinstance(instruction.operator, Gate): @@ -72,9 +78,9 @@ def validate(self, circuit: Circuit) -> None: raise ValueError(f"Gate {gate.name} is not supported by this device.") idx += 1 - def __eq__(self, other: EmulatorCriterion) -> bool: + def __eq__(self, other: ValidationPass) -> bool: return ( - isinstance(other, GateCriterion) + isinstance(other, GateValidator) and self._supported_gates == other._supported_gates and self._native_gates == other._native_gates ) diff --git a/src/braket/emulators/emulator_passes/criteria/qubit_count_criterion.py b/src/braket/emulation/emulator_passes/criteria/qubit_count_validator.py similarity index 68% rename from src/braket/emulators/emulator_passes/criteria/qubit_count_criterion.py rename to src/braket/emulation/emulator_passes/criteria/qubit_count_validator.py index 50eae30e3..5e5b26aff 100644 --- a/src/braket/emulators/emulator_passes/criteria/qubit_count_criterion.py +++ b/src/braket/emulation/emulator_passes/criteria/qubit_count_validator.py @@ -1,11 +1,11 @@ from braket.circuits import Circuit -from braket.emulators.emulator_passes.criteria.emulator_criterion import EmulatorCriterion +from braket.emulation.emulator_passes.criteria.validation_pass import ValidationPass -class QubitCountCriterion(EmulatorCriterion): +class QubitCountValidator(ValidationPass[Circuit]): """ - A simple criterion class that checks that an input program does not use more qubits - than available on a device, as set during this criterion's instantiation. + A simple validator class that checks that an input program does not use more qubits + than available on a device, as set during this validator's instantiation. """ def __init__(self, qubit_count: int): @@ -16,7 +16,7 @@ def __init__(self, qubit_count: int): def validate(self, circuit: Circuit) -> None: """ Checks that the number of qubits used in this circuit does not exceed this - criterion's qubit_count max. + validator's qubit_count max. Args: circuit (Circuit): The Braket circuit whose qubit count to validate. @@ -31,5 +31,5 @@ def validate(self, circuit: Circuit) -> None: but uses {circuit.qubit_count} qubits." ) - def __eq__(self, other: EmulatorCriterion) -> bool: - return isinstance(other, QubitCountCriterion) and self._qubit_count == other._qubit_count + def __eq__(self, other: ValidationPass) -> bool: + return isinstance(other, QubitCountValidator) and self._qubit_count == other._qubit_count diff --git a/src/braket/emulators/emulator_passes/criteria/emulator_criterion.py b/src/braket/emulation/emulator_passes/criteria/validation_pass.py similarity index 56% rename from src/braket/emulators/emulator_passes/criteria/emulator_criterion.py rename to src/braket/emulation/emulator_passes/criteria/validation_pass.py index c12b44057..1641a3f79 100644 --- a/src/braket/emulators/emulator_passes/criteria/emulator_criterion.py +++ b/src/braket/emulation/emulator_passes/criteria/validation_pass.py @@ -2,14 +2,14 @@ from abc import abstractmethod -from braket.emulators.emulator_passes.emulator_pass import EmulatorPass, ProgramType +from braket.emulation.emulator_passes.emulator_pass import EmulationPass, ProgramType -class EmulatorCriterion(EmulatorPass): +class ValidationPass(EmulationPass[ProgramType]): @abstractmethod def validate(self, program: ProgramType) -> None: """ - An emulator criterion is used to perform some non-modifying validation + An emulator validator is used to perform some non-modifying validation pass on an input program. Implementations of validate should return nothing if the input program passes validation and raise an error otherwise. @@ -30,19 +30,3 @@ def run(self, program: ProgramType) -> ProgramType: """ self.validate(program) return program - - @abstractmethod - def __eq__(self, other: EmulatorCriterion) -> bool: - """ - Checks whether or not two EmulatorCriterion are equivalent, i.e. they sets of programs - they validate and invalidate are identical. - - Args: - other (EmulatorCriterion): The other criterion instance to compare with this instance. - - - Raises: - NotImplementedError: Method not implemented. - """ - - raise NotImplementedError diff --git a/src/braket/emulators/emulator_passes/emulator_pass.py b/src/braket/emulation/emulator_passes/emulator_pass.py similarity index 88% rename from src/braket/emulators/emulator_passes/emulator_pass.py rename to src/braket/emulation/emulator_passes/emulator_pass.py index b61b9e9f4..9bbd62b4f 100644 --- a/src/braket/emulators/emulator_passes/emulator_pass.py +++ b/src/braket/emulation/emulator_passes/emulator_pass.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod -from typing import TypeVar +from typing import Generic, TypeVar ProgramType = TypeVar("ProgramType") -class EmulatorPass(ABC): +class EmulationPass(ABC, Generic[ProgramType]): @abstractmethod def run(self, program: ProgramType) -> ProgramType: """ diff --git a/src/braket/emulators/__init__.py b/src/braket/emulators/__init__.py deleted file mode 100644 index 60a33ea70..000000000 --- a/src/braket/emulators/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from braket.emulators.emulator import Emulator # noqa: F40 diff --git a/src/braket/emulators/emulator_passes/__init__.py b/src/braket/emulators/emulator_passes/__init__.py deleted file mode 100644 index 0de674ab4..000000000 --- a/src/braket/emulators/emulator_passes/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from braket.emulators.emulator_passes.criteria import ( # noqa: F401 - ConnectivityCriterion, - EmulatorCriterion, - GateConnectivityCriterion, - GateCriterion, - QubitCountCriterion, -) -from braket.emulators.emulator_passes.emulator_pass import EmulatorPass, ProgramType # noqa: F401 diff --git a/src/braket/emulators/emulator_passes/criteria/__init__.py b/src/braket/emulators/emulator_passes/criteria/__init__.py deleted file mode 100644 index 081defd8c..000000000 --- a/src/braket/emulators/emulator_passes/criteria/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from braket.emulators.emulator_passes.criteria.connectivity_criterion import ( # noqa: F401 - ConnectivityCriterion, -) -from braket.emulators.emulator_passes.criteria.emulator_criterion import ( # noqa: F401 - EmulatorCriterion, -) -from braket.emulators.emulator_passes.criteria.gate_connectivity_criterion import ( # noqa: F401 - GateConnectivityCriterion, -) -from braket.emulators.emulator_passes.criteria.gate_criterion import GateCriterion # noqa: F401 -from braket.emulators.emulator_passes.criteria.qubit_count_criterion import ( # noqa: F401 - QubitCountCriterion, -) diff --git a/test/unit_tests/braket/aws/test_aws_emulation.py b/test/unit_tests/braket/aws/test_aws_emulation.py index cc3167fe9..e36068dce 100644 --- a/test/unit_tests/braket/aws/test_aws_emulation.py +++ b/test/unit_tests/braket/aws/test_aws_emulation.py @@ -30,12 +30,12 @@ from braket.device_schema.rigetti import RigettiDeviceCapabilities from braket.devices import Devices from braket.devices.local_simulator import LocalSimulator -from braket.emulators import Emulator -from braket.emulators.emulator_passes import ( - ConnectivityCriterion, - GateConnectivityCriterion, - GateCriterion, - QubitCountCriterion, +from braket.emulation import Emulator +from braket.emulation.emulator_passes import ( + ConnectivityValidator, + GateConnectivityValidator, + GateValidator, + QubitCountValidator, ) REGION = "us-west-1" @@ -566,13 +566,13 @@ def _device(): def test_ionq_emulator(ionq_device): emulator = ionq_device.emulator target_emulator_passes = [ - QubitCountCriterion(ionq_device.properties.paradigm.qubitCount), - GateCriterion( + QubitCountValidator(ionq_device.properties.paradigm.qubitCount), + GateValidator( supported_gates=["x", "Y"], native_gates=["cz", "gpi", "cphaseshift"], ), - ConnectivityCriterion(nx.from_edgelist([(0, 1), (1, 0)], create_using=nx.DiGraph())), - GateConnectivityCriterion( + ConnectivityValidator(nx.from_edgelist([(0, 1), (1, 0)], create_using=nx.DiGraph())), + GateConnectivityValidator( nx.from_dict_of_dicts( { 0: {1: {"supported_gates": set(["CZ", "CPhaseShift", "GPi"])}}, @@ -598,15 +598,15 @@ def test_rigetti_emulator(rigetti_device, rigetti_target_noise_model): ) target_emulator_passes = [ - QubitCountCriterion(rigetti_device.properties.paradigm.qubitCount), - GateCriterion( + QubitCountValidator(rigetti_device.properties.paradigm.qubitCount), + GateValidator( supported_gates=["H", "X", "CNot", "CZ", "Rx", "Ry", "YY"], native_gates=["cz", "prx", "cphaseshift"], ), - ConnectivityCriterion( + ConnectivityValidator( nx.from_edgelist([(0, 1), (0, 2), (1, 0), (2, 0)], create_using=nx.DiGraph()) ), - GateConnectivityCriterion( + GateConnectivityValidator( nx.from_dict_of_dicts( { 0: { @@ -630,17 +630,17 @@ def test_iqm_emulator(iqm_device, iqm_target_noise_model): assert len(emulator.noise_model.instructions) == len(iqm_target_noise_model.instructions) assert emulator.noise_model.instructions == iqm_target_noise_model.instructions target_emulator_passes = [ - QubitCountCriterion(iqm_device.properties.paradigm.qubitCount), - GateCriterion( + QubitCountValidator(iqm_device.properties.paradigm.qubitCount), + GateValidator( supported_gates=["H", "CNot", "Ry", "XX", "YY"], native_gates=["cz", "prx", "cphaseshift"], ), - ConnectivityCriterion( + ConnectivityValidator( nx.from_edgelist( [(0, 1), (0, 2), (1, 0), (2, 0), (2, 3), (3, 2)], create_using=nx.DiGraph() ) ), - GateConnectivityCriterion( + GateConnectivityValidator( nx.from_dict_of_dicts( { 0: { @@ -691,7 +691,7 @@ def test_get_gate_translations(device_capabilities, gate_name, expected_result, def test_emulator_passes(circuit, is_valid, rigetti_device): if is_valid: rigetti_device.validate(circuit) - assert rigetti_device.run_emulator_passes(circuit, apply_noise_model=False) == circuit + assert rigetti_device.run_passes(circuit, apply_noise_model=False) == circuit else: with pytest.raises(ValueError): rigetti_device.validate(circuit) diff --git a/test/unit_tests/braket/emulation/test_connectivity_criterion.py b/test/unit_tests/braket/emulation/test_connectivity_validator.py similarity index 80% rename from test/unit_tests/braket/emulation/test_connectivity_criterion.py rename to test/unit_tests/braket/emulation/test_connectivity_validator.py index 87afefb5c..ea4478dd8 100644 --- a/test/unit_tests/braket/emulation/test_connectivity_criterion.py +++ b/test/unit_tests/braket/emulation/test_connectivity_validator.py @@ -4,7 +4,7 @@ from networkx.utils import graphs_equal from braket.circuits import Circuit -from braket.emulators.emulator_passes.criteria import ConnectivityCriterion +from braket.emulation.emulator_passes.criteria import ConnectivityValidator @pytest.fixture @@ -39,9 +39,9 @@ def six_node_digraph(): ) def test_basic_contiguous_circuits(basic_2_node_complete_graph, circuit): """ - ConnectivityGateCriterion should not raise any errors when validating these circuits. + ConnectivityValidator should not raise any errors when validating these circuits. """ - ConnectivityCriterion(basic_2_node_complete_graph).validate(circuit) + ConnectivityValidator(basic_2_node_complete_graph).validate(circuit) @pytest.mark.parametrize( @@ -58,18 +58,18 @@ def test_basic_contiguous_circuits(basic_2_node_complete_graph, circuit): ) def test_valid_discontiguous_circuits(basic_noncontig_qubits_2_node_complete_graph, circuit): """ - ConnectivityGateCriterion should not raise any errors when validating these circuits. + ConnectivityValidator should not raise any errors when validating these circuits. """ - ConnectivityCriterion(basic_noncontig_qubits_2_node_complete_graph).validate(circuit) + ConnectivityValidator(basic_noncontig_qubits_2_node_complete_graph).validate(circuit) def test_complete_graph_instantation_with_num_qubits(): """ Tests that, if fully_connected is True and num_qubits are passed into the - ConnectivityCriterion constructor, a fully connected graph is created. + ConnectivityValidator constructor, a fully connected graph is created. """ num_qubits = 5 - criterion = ConnectivityCriterion(num_qubits=num_qubits, fully_connected=True) + validator = ConnectivityValidator(num_qubits=num_qubits, fully_connected=True) vb = Circuit() for i in range(num_qubits): for j in range(num_qubits): @@ -78,19 +78,19 @@ def test_complete_graph_instantation_with_num_qubits(): else: vb.i(i) circuit = Circuit().add_verbatim_box(vb) - criterion.validate(circuit) + validator.validate(circuit) assert nx.utils.graphs_equal( - criterion._connectivity_graph, nx.complete_graph(num_qubits, create_using=nx.DiGraph()) + validator._connectivity_graph, nx.complete_graph(num_qubits, create_using=nx.DiGraph()) ) def test_complete_graph_instantation_with_qubit_labels(): """ Tests that, if fully_connected is True and num_qubits are passed into the - ConnectivityCriterion constructor, a fully connected graph is created. + ConnectivityValidator constructor, a fully connected graph is created. """ qubit_labels = [0, 1, 10, 11, 110, 111, 112, 113] - criterion = ConnectivityCriterion(qubit_labels=qubit_labels, fully_connected=True) + validator = ConnectivityValidator(qubit_labels=qubit_labels, fully_connected=True) vb = Circuit() for i in qubit_labels: for j in qubit_labels: @@ -99,9 +99,9 @@ def test_complete_graph_instantation_with_qubit_labels(): else: vb.i(i) circuit = Circuit().add_verbatim_box(vb) - criterion.validate(circuit) + validator.validate(circuit) assert nx.utils.graphs_equal( - criterion._connectivity_graph, nx.complete_graph(qubit_labels, create_using=nx.DiGraph()) + validator._connectivity_graph, nx.complete_graph(qubit_labels, create_using=nx.DiGraph()) ) @@ -118,7 +118,7 @@ def test_complete_graph_instantation_with_qubit_labels(): ) def test_invalid_2_qubit_gates(six_node_digraph, circuit): with pytest.raises(ValueError): - ConnectivityCriterion(six_node_digraph).validate(circuit) + ConnectivityValidator(six_node_digraph).validate(circuit) @pytest.mark.parametrize( @@ -134,13 +134,13 @@ def test_invalid_2_qubit_gates(six_node_digraph, circuit): ) def test_invalid_1_qubit_gates(six_node_digraph, circuit): with pytest.raises(ValueError): - ConnectivityCriterion(six_node_digraph).validate(circuit) + ConnectivityValidator(six_node_digraph).validate(circuit) def test_equality_graph_created_with_dict(six_node_digraph): graph = {0: [1, 3], 1: [0, 2, 10], 2: [1, 3, 11], 10: [1, 11], 11: [2, 10]} - criteria_from_digraph = ConnectivityCriterion(six_node_digraph) - criteria_from_dict = ConnectivityCriterion(graph) + criteria_from_digraph = ConnectivityValidator(six_node_digraph) + criteria_from_dict = ConnectivityValidator(graph) assert criteria_from_dict == criteria_from_digraph @@ -158,7 +158,7 @@ def test_invalid_constructors( connectivity_graph, fully_connected, num_qubits, qubit_labels, directed ): with pytest.raises(ValueError): - ConnectivityCriterion( + ConnectivityValidator( connectivity_graph, fully_connected, num_qubits, qubit_labels, directed ) @@ -188,7 +188,7 @@ def test_undirected_graph_construction(representation): ], create_using=nx.DiGraph, ) - cc = ConnectivityCriterion(representation, directed=False) + cc = ConnectivityValidator(representation, directed=False) assert graphs_equal(cc._connectivity_graph, expected_digraph) @@ -209,9 +209,9 @@ def test_undirected_graph_construction(representation): ], ) def test_validate_instruction_method(controls, targets, is_valid, six_node_digraph): - gcc = ConnectivityCriterion(six_node_digraph, directed=False) + gcc = ConnectivityValidator(six_node_digraph, directed=False) if is_valid: - gcc.validate_instruction_connectivity(controls, targets) + gcc._validate_instruction_connectivity(controls, targets) else: with pytest.raises(ValueError): - gcc.validate_instruction_connectivity(controls, targets) + gcc._validate_instruction_connectivity(controls, targets) diff --git a/test/unit_tests/braket/emulation/test_emulator.py b/test/unit_tests/braket/emulation/test_emulator.py index 562822f85..a8045052c 100644 --- a/test/unit_tests/braket/emulation/test_emulator.py +++ b/test/unit_tests/braket/emulation/test_emulator.py @@ -9,16 +9,16 @@ from braket.circuits.noises import BitFlip from braket.default_simulator import DensityMatrixSimulator, StateVectorSimulator from braket.devices import local_simulator -from braket.emulators import Emulator -from braket.emulators.emulator_passes import ( - EmulatorPass, - GateCriterion, +from braket.emulation import Emulator +from braket.emulation.emulator_passes import ( + EmulationPass, + GateValidator, ProgramType, - QubitCountCriterion, + QubitCountValidator, ) -class AlwaysFailPass(EmulatorPass): +class AlwaysFailPass(EmulationPass): def run(self, program: ProgramType): raise ValueError("This pass always raises an error.") @@ -40,8 +40,8 @@ def empty_emulator(setup_local_simulator_devices): @pytest.fixture def basic_emulator(empty_emulator): - qubit_count_criterion = QubitCountCriterion(4) - return empty_emulator.add_pass(emulator_pass=[qubit_count_criterion]) + qubit_count_validator = QubitCountValidator(4) + return empty_emulator.add_pass(emulator_pass=[qubit_count_validator]) def test_empty_emulator_validation(empty_emulator): @@ -61,7 +61,7 @@ def test_basic_emulator(basic_emulator): def test_basic_invalidate(basic_emulator): """ - Emulator should raise an error thrown by the QubitCountCriterion. + Emulator should raise an error thrown by the QubitCountValidator. """ circuit = Circuit().x(range(6)) match_string = re.escape( @@ -74,10 +74,10 @@ def test_basic_invalidate(basic_emulator): def test_add_pass_single(empty_emulator): emulator = empty_emulator - qubit_count_criterion = QubitCountCriterion(4) - emulator.add_pass(qubit_count_criterion) + qubit_count_validator = QubitCountValidator(4) + emulator.add_pass(qubit_count_validator) - assert emulator._emulator_passes == [qubit_count_criterion] + assert emulator._emulator_passes == [qubit_count_validator] def test_bad_add_pass(empty_emulator): @@ -87,16 +87,16 @@ def test_bad_add_pass(empty_emulator): def test_add_pass_multiple(setup_local_simulator_devices): - native_gate_criterion = GateCriterion(native_gates=["CZ", "PRx"]) - emulator = Emulator(emulator_passes=[native_gate_criterion]) - qubit_count_criterion = QubitCountCriterion(4) - gate_criterion = GateCriterion(supported_gates=["H", "CNot"]) + native_gate_validator = GateValidator(native_gates=["CZ", "PRx"]) + emulator = Emulator(emulator_passes=[native_gate_validator]) + qubit_count_validator = QubitCountValidator(4) + gate_validator = GateValidator(supported_gates=["H", "CNot"]) - emulator.add_pass([qubit_count_criterion, gate_criterion]) + emulator.add_pass([qubit_count_validator, gate_validator]) assert emulator._emulator_passes == [ - native_gate_criterion, - qubit_count_criterion, - gate_criterion, + native_gate_validator, + qubit_count_validator, + gate_validator, ] @@ -119,9 +119,9 @@ def test_update_noise_model(empty_emulator): def test_validation_only_pass(setup_local_simulator_devices): - qubit_count_criterion = QubitCountCriterion(4) + qubit_count_validator = QubitCountValidator(4) bad_pass = AlwaysFailPass() - emulator = Emulator(emulator_passes=[bad_pass, qubit_count_criterion]) + emulator = Emulator(emulator_passes=[bad_pass, qubit_count_validator]) circuit = Circuit().h(range(5)) match_string = re.escape( @@ -151,9 +151,9 @@ def test_apply_noise_model(setup_local_simulator_devices): def test_noiseless_run(setup_local_simulator_devices): - qubit_count_criterion = QubitCountCriterion(4) - gate_criterion = GateCriterion(supported_gates=["H"]) - emulator = Emulator(emulator_passes=[qubit_count_criterion, gate_criterion]) + qubit_count_validator = QubitCountValidator(4) + gate_validator = GateValidator(supported_gates=["H"]) + emulator = Emulator(emulator_passes=[qubit_count_validator, gate_validator]) circuit = Circuit().h(0).state_vector() result = emulator.run(circuit).result() @@ -166,11 +166,11 @@ def test_noisy_run(setup_local_simulator_devices): noise_model = NoiseModel() noise_model.add_noise(BitFlip(0.1), GateCriteria(Gate.H)) - qubit_count_criterion = QubitCountCriterion(4) - gate_criterion = GateCriterion(supported_gates=["H"]) + qubit_count_validator = QubitCountValidator(4) + gate_validator = GateValidator(supported_gates=["H"]) emulator = Emulator( backend="braket_dm", - emulator_passes=[qubit_count_criterion, gate_criterion], + emulator_passes=[qubit_count_validator, gate_validator], noise_model=noise_model, ) diff --git a/test/unit_tests/braket/emulation/test_gate_connectivity_criterion.py b/test/unit_tests/braket/emulation/test_gate_connectivity_validator.py similarity index 85% rename from test/unit_tests/braket/emulation/test_gate_connectivity_criterion.py rename to test/unit_tests/braket/emulation/test_gate_connectivity_validator.py index c0575c3e8..6b81cc110 100644 --- a/test/unit_tests/braket/emulation/test_gate_connectivity_criterion.py +++ b/test/unit_tests/braket/emulation/test_gate_connectivity_validator.py @@ -5,7 +5,7 @@ from braket.circuits import Circuit, Gate from braket.circuits.noises import BitFlip -from braket.emulators.emulator_passes.criteria import GateConnectivityCriterion +from braket.emulation.emulator_passes.criteria import GateConnectivityValidator @pytest.fixture @@ -66,10 +66,10 @@ def basic_4_node_graph_as_dict(): ) def test_valid_basic_contiguous_circuits(basic_4_node_graph, circuit): """ - ConnectivityGateCriterion should not raise any errors when validating these circuits. + GateConnectivityValidator should not raise any errors when validating these circuits. """ - gate_connectivity_criterion = GateConnectivityCriterion(basic_4_node_graph) - gate_connectivity_criterion.validate(circuit) + gate_connectivity_validator = GateConnectivityValidator(basic_4_node_graph) + gate_connectivity_validator.validate(circuit) @pytest.mark.parametrize( @@ -92,15 +92,15 @@ def test_valid_basic_contiguous_circuits(basic_4_node_graph, circuit): ) def test_valid_basic_discontiguous_circuits(basic_discontiguous_4_node_graph, circuit): """ - ConnectivityGateCriterion should not raise any errors when validating these circuits. + GateConnectivityValidator should not raise any errors when validating these circuits. """ - gate_connectivity_criterion = GateConnectivityCriterion(basic_discontiguous_4_node_graph) - gate_connectivity_criterion.validate(circuit) + gate_connectivity_validator = GateConnectivityValidator(basic_discontiguous_4_node_graph) + gate_connectivity_validator.validate(circuit) def test_directed_graph_construction_from_dict(): """ - ConnectivityGateCriterion should correctly construct a graph from a dictionary + GateConnectivityValidator should correctly construct a graph from a dictionary representation of the connectivity. """ dict_representation = { @@ -118,7 +118,7 @@ def test_directed_graph_construction_from_dict(): (2, 5, {"supported_gates": ["XX", "XY", "CNot", "CZ"]}), ] ) - gcc = GateConnectivityCriterion(dict_representation) + gcc = GateConnectivityValidator(dict_representation) assert graphs_equal(gcc._gate_connectivity_graph, digraph_representation) @@ -140,17 +140,17 @@ def test_directed_graph_construction_from_dict(): ) def test_undirected_criteria_from_dict_with_valid_circuits(basic_4_node_graph_as_dict, circuit): """ - ConnectivityGateCriterion should not raise any errors when validating these circuits. + GateConnectivityValidator should not raise any errors when validating these circuits. """ - gate_connectivity_criterion = GateConnectivityCriterion( + gate_connectivity_validator = GateConnectivityValidator( basic_4_node_graph_as_dict, directed=False ) - gate_connectivity_criterion.validate(circuit) + gate_connectivity_validator.validate(circuit) def test_undirected_graph_construction_from_dict(): """ - ConnectivityGateCriterion should correctly construct an undirected graph from a dictionary + GateConnectivityValidator should correctly construct an undirected graph from a dictionary representation of the connectivity. """ dict_representation = { @@ -173,7 +173,7 @@ def test_undirected_graph_construction_from_dict(): (5, 2, {"supported_gates": ["XX", "XY", "CNot", "CZ"]}), ] ) - gcc = GateConnectivityCriterion(dict_representation, directed=False) + gcc = GateConnectivityValidator(dict_representation, directed=False) assert graphs_equal(gcc._gate_connectivity_graph, digraph_representation) @@ -199,7 +199,7 @@ def test_undirected_graph_construction_from_dict(): def test_undirected_graph_from_digraph(edges): """ Check that undirected topologies created from a digraph correctly add all possible - back edges to the criterion's connectivity graph. + back edges to the validator's connectivity graph. """ directed_graph = nx.DiGraph() directed_graph.add_edges_from(edges) @@ -209,10 +209,10 @@ def test_undirected_graph_from_digraph(edges): if (edge[1], edge[0]) not in undirected_graph.edges: undirected_graph.add_edges_from([(edge[1], edge[0], edge[2])]) - gcc = GateConnectivityCriterion(directed_graph, directed=False) + gcc = GateConnectivityValidator(directed_graph, directed=False) assert graphs_equal(gcc._gate_connectivity_graph, undirected_graph) - gcc_other = GateConnectivityCriterion(undirected_graph) + gcc_other = GateConnectivityValidator(undirected_graph) assert gcc_other == gcc @@ -236,7 +236,7 @@ def create_undirected_graph_with_exisiting_back_edges(representation): is created properly. """ - gcc = GateConnectivityCriterion(representation, directed=False) + gcc = GateConnectivityValidator(representation, directed=False) expected_digraph_representation = nx.DiGraph() expected_digraph_representation.add_edges_from( [ @@ -261,14 +261,14 @@ def create_undirected_graph_with_exisiting_back_edges(representation): ) def test_invalid_circuits(basic_4_node_graph, circuit): with pytest.raises(ValueError): - gate_connectivity_criterion = GateConnectivityCriterion(basic_4_node_graph) - gate_connectivity_criterion.validate(circuit) + gate_connectivity_validator = GateConnectivityValidator(basic_4_node_graph) + gate_connectivity_validator.validate(circuit) def test_invalid_connectivity_graph(): bad_graph = nx.complete_graph(5, create_using=nx.Graph()) with pytest.raises(TypeError): - GateConnectivityCriterion(bad_graph) + GateConnectivityValidator(bad_graph) @pytest.mark.parametrize( @@ -283,12 +283,12 @@ def test_invalid_connectivity_graph(): ], ) def test_validate_instruction_method(gate_name, controls, targets, is_valid, basic_4_node_graph): - gcc = GateConnectivityCriterion(basic_4_node_graph, directed=False) + gcc = GateConnectivityValidator(basic_4_node_graph, directed=False) if is_valid: - gcc.validate_instruction_connectivity(gate_name, controls, targets) + gcc._validate_instruction_connectivity(gate_name, controls, targets) else: with pytest.raises(ValueError): - gcc.validate_instruction_connectivity(gate_name, controls, targets) + gcc._validate_instruction_connectivity(gate_name, controls, targets) @pytest.mark.parametrize( @@ -309,4 +309,4 @@ def test_validate_instruction_method(gate_name, controls, targets, is_valid, bas ) def test_invalid_undirected_graph(graph): with pytest.raises(ValueError): - GateConnectivityCriterion(graph, directed=False) + GateConnectivityValidator(graph, directed=False) diff --git a/test/unit_tests/braket/emulation/test_gate_criterion.py b/test/unit_tests/braket/emulation/test_gate_validator.py similarity index 82% rename from test/unit_tests/braket/emulation/test_gate_criterion.py rename to test/unit_tests/braket/emulation/test_gate_validator.py index 9f85969d6..2003b629f 100644 --- a/test/unit_tests/braket/emulation/test_gate_criterion.py +++ b/test/unit_tests/braket/emulation/test_gate_validator.py @@ -4,7 +4,7 @@ from braket.circuits import Circuit, Gate, Instruction from braket.circuits.compiler_directives import StartVerbatimBox from braket.circuits.noises import BitFlip -from braket.emulators.emulator_passes.criteria import GateCriterion +from braket.emulation.emulator_passes.criteria import GateValidator @pytest.fixture @@ -74,43 +74,43 @@ def mock_qpu_gates(): ) def test_valid_circuits(mock_qpu_gates, circuit): """ - GateCriterion should not raise any errors when validating these circuits. + GateValidator should not raise any errors when validating these circuits. """ - GateCriterion(mock_qpu_gates[0], mock_qpu_gates[1]).validate(circuit) + GateValidator(mock_qpu_gates[0], mock_qpu_gates[1]).validate(circuit) def test_only_supported_gates(): supported_gates = ["h", "cnot", "rx", "xx", "y"] - criterion = GateCriterion(supported_gates=supported_gates) + validator = GateValidator(supported_gates=supported_gates) circuit = Circuit().h(0).cnot(0, 1).rx(4, np.pi / 4).xx(2, 3, np.pi / 4).y(7) - criterion.validate(circuit) + validator.validate(circuit) def test_verbatim_circuit_only_supported_gates(): supported_gates = ["h", "cnot", "rx", "xx", "y"] - criterion = GateCriterion(supported_gates=supported_gates) + validator = GateValidator(supported_gates=supported_gates) circuit = Circuit().add_verbatim_box(Circuit().h(0)) with pytest.raises(ValueError): - criterion.validate(circuit) + validator.validate(circuit) def test_only_native_gates(): native_gates = ["h", "cnot", "rx", "xx", "y"] - criterion = GateCriterion(native_gates=native_gates) + validator = GateValidator(native_gates=native_gates) vb = Circuit().h(0).cnot(0, 1).rx(4, np.pi / 4).xx(2, 3, np.pi / 4).y(7) circuit = Circuit().add_verbatim_box(vb) - criterion.validate(circuit) + validator.validate(circuit) def test_non_verbatim_circuit_only_native_gates(): native_gates = ["h", "cnot", "rx", "xx", "y"] - criterion = GateCriterion(native_gates=native_gates) + validator = GateValidator(native_gates=native_gates) vb = Circuit().h(0).cnot(0, 1).rx(4, np.pi / 4).xx(2, 3, np.pi / 4).y(7) circuit = Circuit().add_verbatim_box(vb) circuit.i(0) with pytest.raises(ValueError): - criterion.validate(circuit) + validator.validate(circuit) @pytest.mark.parametrize( @@ -128,7 +128,7 @@ def test_non_verbatim_circuit_only_native_gates(): ) def test_invalid_instantiation(supported_gates, native_gates, error_message): with pytest.raises(ValueError, match=error_message): - GateCriterion(supported_gates, native_gates) + GateValidator(supported_gates, native_gates) @pytest.mark.parametrize( @@ -147,10 +147,10 @@ def test_invalid_instantiation(supported_gates, native_gates, error_message): ) def test_invalid_circuits(basic_gate_set, circuit): """ - GateCriterion should raise errors when validating these circuits. + GateValidator should raise errors when validating these circuits. """ with pytest.raises(ValueError): - GateCriterion(basic_gate_set[0], basic_gate_set[1]).validate(circuit) + GateValidator(basic_gate_set[0], basic_gate_set[1]).validate(circuit) @pytest.mark.parametrize( @@ -162,7 +162,7 @@ def test_invalid_circuits(basic_gate_set, circuit): ], ) def test_equality(gate_set_1, gate_set_2): - assert GateCriterion(gate_set_1) == GateCriterion(gate_set_2) + assert GateValidator(gate_set_1) == GateValidator(gate_set_2) @pytest.mark.parametrize( @@ -175,4 +175,4 @@ def test_equality(gate_set_1, gate_set_2): ], ) def test_inequality(gate_set_1, gate_set_2): - assert GateCriterion(gate_set_1) != GateCriterion(gate_set_2) + assert GateValidator(gate_set_1) != GateValidator(gate_set_2) diff --git a/test/unit_tests/braket/emulation/test_qubit_count_criterion.py b/test/unit_tests/braket/emulation/test_qubit_count_validator.py similarity index 74% rename from test/unit_tests/braket/emulation/test_qubit_count_criterion.py rename to test/unit_tests/braket/emulation/test_qubit_count_validator.py index c487e2eab..1007d726b 100644 --- a/test/unit_tests/braket/emulation/test_qubit_count_criterion.py +++ b/test/unit_tests/braket/emulation/test_qubit_count_validator.py @@ -2,7 +2,7 @@ import pytest from braket.circuits import Circuit -from braket.emulators.emulator_passes import QubitCountCriterion +from braket.emulation.emulator_passes import QubitCountValidator @pytest.mark.parametrize( @@ -19,15 +19,15 @@ ) def test_valid_circuits(qubit_count, circuit): """ - QubitCountCriterion should not raise any errors when validating these circuits. + QubitCountValidator should not raise any errors when validating these circuits. """ - QubitCountCriterion(qubit_count=qubit_count).__call__(circuit) + QubitCountValidator(qubit_count=qubit_count).__call__(circuit) @pytest.mark.parametrize("qubit_count", [0, -1]) def test_invalid_instantiation(qubit_count): with pytest.raises(ValueError): - QubitCountCriterion(qubit_count) + QubitCountValidator(qubit_count) @pytest.mark.parametrize( @@ -44,12 +44,12 @@ def test_invalid_circuits(qubit_count, circuit): match=f"Circuit must use at most {qubit_count} qubits, \ but uses {circuit.qubit_count} qubits.", ): - QubitCountCriterion(qubit_count).validate(circuit) + QubitCountValidator(qubit_count).validate(circuit) def test_equality(): - qcc_1 = QubitCountCriterion(1) - qcc_2 = QubitCountCriterion(2) + qcc_1 = QubitCountValidator(1) + qcc_2 = QubitCountValidator(2) assert qcc_1 != qcc_2 - assert qcc_1 == QubitCountCriterion(1) + assert qcc_1 == QubitCountValidator(1)