From 818e37effb6ca9542e6d1a08470bd4d2672b8d82 Mon Sep 17 00:00:00 2001 From: Nagji Date: Tue, 16 Jul 2024 16:14:52 -0700 Subject: [PATCH 01/10] feat: Extend AHS validation to include additional QPU specific restrictions --- .../device_atom_arrangement.py | 105 ++++++++++ .../device_capabilities_constants.py | 23 +++ .../device_validators/device_driving_filed.py | 182 ++++++++++++++++++ .../device_local_detuning.py | 82 ++++++++ .../validators/field_validator_util.py | 45 +++++ 5 files changed, 437 insertions(+) create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py new file mode 100644 index 00000000..7bb306e3 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -0,0 +1,105 @@ +from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement import ( + AtomArrangementValidator +) +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( + PhysicalField +) +from device_capabilities_constants import DeviceCapabilitiesConstants +from pydantic.v1.class_validators import root_validator +from decimal import Decimal +from typing import Tuple + + +def _y_distance(site_1: Tuple[Decimal, Decimal], site_2: Tuple[Decimal, Decimal]) -> Decimal: + # Compute the y-separation between two sets of 2-D points, (x1, y1) and (x2, y2) + + return Decimal(abs(site_1[1] - site_2[1])) + + +class DeviceAtomArrangement(AtomArrangementValidator): + capabilities: DeviceCapabilitiesConstants + + @root_validator(pre=True, skip_on_failure=True) + def sites_not_empty(cls, values): + sites = values["sites"] + if not sites: + raise ValueError("Sites can not be empty.") + return values + + + # Each site has two coordinates (minItems=maxItems=2) + @root_validator(pre=True, skip_on_failure=True) + def filling_not_empty(cls, values): + filling = values["filling"] + if not filling: + raise ValueError("Filling can not be empty.") + return values + + + # The maximum allowable precision in the coordinates is SITE_PRECISION + @root_validator(pre=True, skip_on_failure=True) + def sites_defined_with_right_precision(cls, values): + sites = values["sites"] + capabilities = values["capabilities"] + for idx, s in enumerate(sites): + if not all( + [Decimal(str(coordinate)) % capabilities.SITE_PRECISION == 0 for coordinate in s] + ): + raise ValueError( + f"Coordinates {idx}({s}) is defined with too high precision; they must be multiples of {capabilities.SITE_PRECISION} meters" + ) + return values + + # Number of sites must not exceeds MAX_SITES + @root_validator(pre=True, skip_on_failure=True) + def sites_not_too_many(cls, values): + sites = values["sites"] + capabilities = values["capabilities"] + num_sites = len(sites) + if num_sites > capabilities.MAX_SITES: + raise ValueError( + f"There are too many sites ({num_sites}); there must be at most {capabilities.MAX_SITES} sites" + ) + return values + + # The y coordinates of any two lattice sites must either be equal or differ by at least MIN_ROW_DISTANCE. + @root_validator(pre=True, skip_on_failure=True) + def sites_in_rows(cls, values): + sites = values["sites"] + capabilities = values["capabilities"] + sorted_sites = sorted(sites, key=lambda xy: xy[1]) + min_allowed_distance = capabilities.MIN_ROW_DISTANCE + if values["feature_access"]: + min_allowed_distance = Decimal("0.000002") + for s1, s2 in zip(sorted_sites[:-1], sorted_sites[1:]): + row_distance = _y_distance(s1, s2) + if row_distance == 0: + continue + if row_distance < min_allowed_distance: + raise ValueError( + f"Sites {s1} and site {s2} have y-separation ({row_distance}). It must either be exactly zero or not smaller than {min_allowed_distance} meters" + ) + return values + + + # The number of filled lattice sites must not exceed MAX_FILLED_SITES. + @root_validator(pre=True, skip_on_failure=True) + def atom_number_limit(cls, values): + filling = values["filling"] + capabilities = values["capabilities"] + qubits = sum(filling) + if qubits > capabilities.MAX_FILLED_SITES: + raise ValueError( + f"Filling has {qubits} '1' entries; is must have not more than {capabilities.MAX_FILLED_SITES}" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def phase_value_precision_is_correct(cls, values): + phase = values["phase"] + capabilities = values["capabilities"] + phase_obj = PhysicalField.parse_obj(phase) + validate_value_precision( + phase_obj.time_series.values, capabilities.GLOBAL_PHASE_VALUE_PRECISION, "phase" + ) + return values \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py new file mode 100644 index 00000000..fdf2ff86 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py @@ -0,0 +1,23 @@ +from braket.analog_hamiltonian_simulator.rydberg.validators.capabilities_constants import ( + CapabilitiesConstants +) +from decimal import Decimal +from pydantic import PositiveInt + + +class DeviceCapabilitiesConstants(CapabilitiesConstants): + MAX_SITES: int + SITE_PRECISION: Decimal + MAX_FILLED_SITES: int + + GLOBAL_TIME_PRECISION: Decimal + GLOBAL_AMPLITUDE_VALUE_PRECISION: Decimal + GLOBAL_AMPLITUDE_SLOPE_MAX: Decimal + GLOBAL_DETUNING_VALUE_PRECISION: Decimal + GLOBAL_DETUNING_SLOPE_MAX: Decimal + + LOCAL_MAGNITUDE_SLOPE_MAX: Decimal + LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES: Decimal + LOCAL_TIME_PRECISION: Decimal + LOCAL_MIN_TIME_SEPARATION: Decimal + \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py new file mode 100644 index 00000000..03da4a04 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py @@ -0,0 +1,182 @@ +from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import ( + DrivingFieldValidator +) +from device_capabilities_constants import DeviceCapabilitiesConstants +from pydantic.v1.class_validators import root_validator +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( + PhysicalField +) +from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( + validate_time_precision, + validate_time_separation, + validate_value_precision, + validate_max_absolute_slope, + validate_value_range_with_warning +) + +class DeviceDrivingFieldValidator(DrivingFieldValidator): + capabilities: DeviceCapabilitiesConstants + + # Amplitude must start and end at 0.0 + @root_validator(pre=True, skip_on_failure=True) + def amplitude_start_and_end_values(cls, values): + amplitude = values["amplitude"] + time_series = amplitude["time_series"] + time_series_values = time_series["values"] + if time_series_values: + start_value, end_value = time_series_values[0], time_series_values[-1] + if start_value != 0 or end_value != 0: + raise ValueError( + f"The values of the Rabi frequency at the first and last time points are {start_value}, {end_value}; they both must be both 0." + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def amplitude_time_precision_is_correct(cls, values): + amplitude = values["amplitude"] + capabilities = values["capabilities"] + amplitude_obj = PhysicalField.parse_obj(amplitude) + validate_time_precision( + amplitude_obj.time_series.times, capabilities.GLOBAL_TIME_PRECISION, "amplitude" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def amplitude_timepoint_not_too_close(cls, values): + amplitude = values["amplitude"] + capabilities = values["capabilities"] + validate_time_separation( + amplitude["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "amplitude" + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def amplitude_value_precision_is_correct(cls, values): + amplitude = values["amplitude"] + capabilities = values["capabilities"] + amplitude_obj = PhysicalField.parse_obj(amplitude) + validate_value_precision( + amplitude_obj.time_series.values, + capabilities.GLOBAL_AMPLITUDE_VALUE_PRECISION, + "amplitude", + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def amplitude_slopes_not_too_steep(cls, values): + amplitude = values["amplitude"] + capabilities = values["capabilities"] + amplitude_times = amplitude["time_series"]["times"] + amplitude_values = amplitude["time_series"]["values"] + if amplitude_times and amplitude_values: + validate_max_absolute_slope( + amplitude_times, + amplitude_values, + capabilities.GLOBAL_AMPLITUDE_SLOPE_MAX, + "amplitude", + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def phase_time_precision_is_correct(cls, values): + phase = values["phase"] + capabilities = values["capabilities"] + phase_obj = PhysicalField.parse_obj(phase) + validate_time_precision( + phase_obj.time_series.times, capabilities.GLOBAL_TIME_PRECISION, "phase" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def phase_timepoint_not_too_close(cls, values): + phase = values["phase"] + capabilities = values["capabilities"] + validate_time_separation( + phase["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "phase" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def phase_values_start_with_0(cls, values): + phase = values["phase"] + phase_values = phase["time_series"]["values"] + if phase_values: + if phase_values[0] != 0: + raise ValueError( + f"The first value of of driving field phase is {phase_values[0]}; it must be 0." + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def phase_values_within_range(cls, values): + phase = values["phase"] + capabilities = values["capabilities"] + validate_value_range_with_warning( + phase["time_series"]["values"], + capabilities.GLOBAL_PHASE_VALUE_MIN, + capabilities.GLOBAL_PHASE_VALUE_MAX, + "phase", + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def phase_value_precision_is_correct(cls, values): + phase = values["phase"] + capabilities = values["capabilities"] + phase_obj = PhysicalField.parse_obj(phase) + validate_value_precision( + phase_obj.time_series.values, capabilities.GLOBAL_PHASE_VALUE_PRECISION, "phase" + ) + return values + + + @root_validator(pre=True, skip_on_failure=True) + def detuning_time_precision_is_correct(cls, values): + detuning = values["detuning"] + capabilities = values["capabilities"] + detuning_obj = PhysicalField.parse_obj(detuning) + validate_time_precision( + detuning_obj.time_series.times, capabilities.GLOBAL_TIME_PRECISION, "detuning" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def detuning_timepoint_not_too_close(cls, values): + detuning = values["detuning"] + capabilities = values["capabilities"] + validate_time_separation( + detuning["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "detuning" + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def detuning_value_precision_is_correct(cls, values): + detuning = values["detuning"] + capabilities = values["capabilities"] + detuning_obj = PhysicalField.parse_obj(detuning) + validate_value_precision( + detuning_obj.time_series.values, + capabilities.GLOBAL_DETUNING_VALUE_PRECISION, + "detuning", + ) + return values + + @root_validator(pre=True, skip_on_failure=True) + def detuning_slopes_not_too_steep(cls, values): + detuning = values["detuning"] + capabilities = values["capabilities"] + detuning_times = detuning["time_series"]["times"] + detuning_values = detuning["time_series"]["values"] + if detuning_times and detuning_values: + validate_max_absolute_slope( + detuning_times, + detuning_values, + capabilities.GLOBAL_DETUNING_SLOPE_MAX, + "detuning", + ) + return values \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py new file mode 100644 index 00000000..fff39d01 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py @@ -0,0 +1,82 @@ +from braket.analog_hamiltonian_simulator.rydberg.validators.local_detuning import ( + LocalDetuningValidator +) +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( + PhysicalField +) +from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( + validate_time_precision, + validate_max_absolute_slope, + validate_time_separation +) +from pydantic.v1.class_validators import root_validator +from device_capabilities_constants import ( + DeviceCapabilitiesConstants +) + +class DeviceLocalDetuningValidator(LocalDetuningValidator): + capabilities: DeviceCapabilitiesConstants + + # Rule: The number of locally-addressed sites must not exceed rydberg.local.number_local_detuning_sites + @root_validator(pre=True, skip_on_failure=True) + def magnitude_pattern_have_not_too_many_nonzeros(cls, values): + magnitude = values["magnitude"] + capabilities = values["capabilities"] + pattern = magnitude["pattern"] + num_nonzeros = sum([p != 0.0 for p in pattern]) + if num_nonzeros > capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES: + raise ValueError( + f"Number of nonzero magnitude pattern values is {num_nonzeros}; it must not be more than {capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES}" + ) + return values + + # Rule: The Rydberg local detuning times have a resolution of at least rydberg.local.time_resolution + @root_validator(pre=True, skip_on_failure=True) + def magnitude_time_precision_is_correct(cls, values): + magnitude = values["magnitude"] + capabilities = values["capabilities"] + magnitude_obj = PhysicalField.parse_obj(magnitude) + validate_time_precision( + magnitude_obj.time_series.times, capabilities.LOCAL_TIME_PRECISION, "magnitude" + ) + return values + + # Rule: The Rydberg local detuning times must be spaced at least rydberg.local.time_delta_min + @root_validator(pre=True, skip_on_failure=True) + def magnitude_timepoint_not_too_close(cls, values): + magnitude = values["magnitude"] + capabilities = values["capabilities"] + times = magnitude["time_series"]["times"] + validate_time_separation(times, capabilities.LOCAL_MIN_TIME_SEPARATION, "magnitude") + return values + + + # Rule: The Rydberg local detuning slew rate must not exceed rydberg.local.detuning_slew_rate_max + @root_validator(pre=True, skip_on_failure=True) + def magnitude_slopes_not_too_steep(cls, values): + magnitude = values["magnitude"] + capabilities = values["capabilities"] + magnitude_times = magnitude["time_series"]["times"] + magnitude_values = magnitude["time_series"]["values"] + if magnitude_times and magnitude_values: + validate_max_absolute_slope( + magnitude_times, + magnitude_values, + capabilities.LOCAL_MAGNITUDE_SLOPE_MAX, + "magnitude", + ) + return values + + # Rule: The Rydberg local detuning must start and end at 0. + @root_validator(pre=True, skip_on_failure=True) + def local_detuning_start_and_end_values(cls, values): + magnitude = values["magnitude"] + time_series = magnitude["time_series"] + time_series_values = time_series["values"] + if time_series_values: + start_value, end_value = time_series_values[0], time_series_values[-1] + if start_value != 0 or end_value != 0: + raise ValueError( + f"The values of the shifting field magnitude time series at the first and last time points are {start_value}, {end_value}; they both must be both 0." + ) + return values \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py index e34fadea..4525fee2 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py @@ -104,3 +104,48 @@ def validate_net_detuning_with_warning( # Return immediately if there is an atom has net detuning # exceeding MAX_NET_DETUNING at a time point return program + + +def validate_pattern_precision(values: List[Decimal], max_precision: Decimal, name: str): + # Raise ValueError if at any item in the values is beyond the max allowable precision + for idx, v in enumerate(values): + if v % max_precision != 0: + raise ValueError( + f"Value {idx} ({v}) in {name} pattern is defined with too many digits; it must be an integer mutiple of {max_precision}" + ) + +# Two time points cannot be too close, assuming the time points are sorted ascendingly +def validate_time_separation(times: List[Decimal], min_time_separation: Decimal, name: str): + for i in range(len(times) - 1): + time_diff = times[i + 1] - times[i] + if time_diff < min_time_separation: + raise ValueError( + f"Time points of {name} time_series, {i} ({times[i]}) and {i+1} ({times[i+1]}), are too close; they are separated by {time_diff} seconds. It must be at least {min_time_separation} seconds" + ) + + +def validate_value_precision(values: List[Decimal], max_precision: Decimal, name: str): + # Raise ValueError if at any item in the values is beyond the max allowable precision + for idx, v in enumerate(values): + if v % max_precision != 0: + raise ValueError( + f"Value {idx} ({v}) in {name} time_series is defined with too many digits; it must be an integer mutiple of {max_precision}" + ) + +def validate_max_absolute_slope( + times: List[Decimal], values: List[Decimal], max_slope: Decimal, name: str +): + # Raise ValueError if at any time the time series (times, values) rises/falls faster than allowed + for idx in range(len(values) - 1): + slope = (values[idx + 1] - values[idx]) / (times[idx + 1] - times[idx]) + if abs(slope) > max_slope: + raise ValueError( + f"For the {name} field, rate of change of values (between the {idx}-th and the {idx+1}-th times) is {abs(slope)}, more than {max_slope}" + ) + +def validate_time_precision(times: List[Decimal], time_precision: Decimal, name: str): + for idx, t in enumerate(times): + if t % time_precision != 0: + raise ValueError( + f"time point {idx} ({t}) of {name} time_series is defined with too many digits; it must be an integer multple of {time_precision}" + ) \ No newline at end of file From dfe7dcd6c251389cd8a786429d5c0de3b7109186 Mon Sep 17 00:00:00 2001 From: Nagji Date: Thu, 18 Jul 2024 12:20:58 -0700 Subject: [PATCH 02/10] feat: Check for Local Rdyberg capabilities in Device Local Detuning validator, add validators for device constraints. --- .../device_atom_arrangement.py | 4 +- .../device_capabilities_constants.py | 16 +++-- ...iving_filed.py => device_driving_field.py} | 2 +- .../device_validators/device_ir_validator.py | 66 +++++++++++++++++++ .../device_local_detuning.py | 18 +++-- .../rydberg/validators/local_detuning.py | 6 ++ 6 files changed, 101 insertions(+), 11 deletions(-) rename src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/{device_driving_filed.py => device_driving_field.py} (97%) create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index 7bb306e3..386dd72d 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -4,7 +4,7 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( PhysicalField ) -from device_capabilities_constants import DeviceCapabilitiesConstants +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants from pydantic.v1.class_validators import root_validator from decimal import Decimal from typing import Tuple @@ -16,7 +16,7 @@ def _y_distance(site_1: Tuple[Decimal, Decimal], site_2: Tuple[Decimal, Decimal] return Decimal(abs(site_1[1] - site_2[1])) -class DeviceAtomArrangement(AtomArrangementValidator): +class DeviceAtomArrangementValidator(AtomArrangementValidator): capabilities: DeviceCapabilitiesConstants @root_validator(pre=True, skip_on_failure=True) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py index fdf2ff86..19b09fa8 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py @@ -3,6 +3,7 @@ ) from decimal import Decimal from pydantic import PositiveInt +from typing import Optional class DeviceCapabilitiesConstants(CapabilitiesConstants): @@ -16,8 +17,15 @@ class DeviceCapabilitiesConstants(CapabilitiesConstants): GLOBAL_DETUNING_VALUE_PRECISION: Decimal GLOBAL_DETUNING_SLOPE_MAX: Decimal - LOCAL_MAGNITUDE_SLOPE_MAX: Decimal - LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES: Decimal - LOCAL_TIME_PRECISION: Decimal - LOCAL_MIN_TIME_SEPARATION: Decimal + LOCAL_RYDBERG_CAPABILITIES: bool = False + LOCAL_MAGNITUDE_SLOPE_MAX: Optional[Decimal] + LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES: Optional[Decimal] + LOCAL_TIME_PRECISION: Optional[Decimal] + LOCAL_MIN_TIME_SEPARATION: Optional[Decimal] + LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN: Optional[Decimal] + LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX: Optional[Decimal] + + MAGNITUDE_PATTERN_VALUE_MIN: Optional[Decimal] + MAGNITUDE_PATTERN_VALUE_MAX: Optional[Decimal] + MAX_NET_DETUNING: Optional[Decimal] \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py similarity index 97% rename from src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py rename to src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py index 03da4a04..4aca9dff 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_filed.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py @@ -1,7 +1,7 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import ( DrivingFieldValidator ) -from device_capabilities_constants import DeviceCapabilitiesConstants +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants from pydantic.v1.class_validators import root_validator from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( PhysicalField diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py new file mode 100644 index 00000000..009ffac3 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py @@ -0,0 +1,66 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + +from braket.ir.ahs.program_v1 import Program + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( + DeviceAtomArrangementValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( + DeviceCapabilitiesConstants +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( + DeviceDrivingFieldValidator +) +from braket.analog_hamiltonian_simulator.rydberg.validators.hamiltonian import HamiltonianValidator +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( + DeviceLocalDetuningValidator +) +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( + PhysicalFieldValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.program import ProgramValidator +from braket.analog_hamiltonian_simulator.rydberg.validators.times_series import TimeSeriesValidator + + +def validate_program(program: Program, device_capabilities: DeviceCapabilitiesConstants) -> None: + """ + Validate the analog Hamiltonian simulation program has only one driving and shifting field, + and all the sequences have the same last time point. + + Args: + program (Program): An analog Hamiltonian simulation program + device_capabilities (CapabilitiesConstants): The capability constants for the simulator + """ + + ProgramValidator(capabilities=device_capabilities, **program.dict()) + DeviceAtomArrangementValidator(capabilities=device_capabilities, **program.setup.ahs_register.dict()) + HamiltonianValidator(**program.hamiltonian.dict()) + for d_fields in program.hamiltonian.drivingFields: + DeviceDrivingFieldValidator(capabilities=device_capabilities, **d_fields.dict()) + amplitude = d_fields.amplitude + phase = d_fields.phase + detuning = d_fields.detuning + PhysicalFieldValidator(**amplitude.dict()) + TimeSeriesValidator(capabilities=device_capabilities, **amplitude.time_series.dict()) + + PhysicalFieldValidator(**phase.dict()) + TimeSeriesValidator(capabilities=device_capabilities, **phase.time_series.dict()) + + PhysicalFieldValidator(**detuning.dict()) + TimeSeriesValidator(capabilities=device_capabilities, **detuning.time_series.dict()) + for s_fields in program.hamiltonian.localDetuning: + DeviceLocalDetuningValidator(capabilities=device_capabilities, **s_fields.dict()) + magnitude = s_fields.magnitude + PhysicalFieldValidator(**magnitude.dict()) + TimeSeriesValidator(capabilities=device_capabilities, **magnitude.time_series.dict()) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py index fff39d01..8e155a16 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py @@ -10,13 +10,23 @@ validate_time_separation ) from pydantic.v1.class_validators import root_validator -from device_capabilities_constants import ( - DeviceCapabilitiesConstants -) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_capabilities_constants import DeviceCapabilitiesConstants + class DeviceLocalDetuningValidator(LocalDetuningValidator): capabilities: DeviceCapabilitiesConstants + @root_validator(pre=True, skip_on_failure=True) + def check_local_rydberg_capabilities(cls, values): + capabilities = values["capabilities"] + if not capabilities.LOCAL_RYDBERG_CAPABILITIES: + raise ValueError( + "Local Rydberg capabilities information has not been \ + provided for local detuning." + ) + + # Rule: The number of locally-addressed sites must not exceed rydberg.local.number_local_detuning_sites @root_validator(pre=True, skip_on_failure=True) def magnitude_pattern_have_not_too_many_nonzeros(cls, values): @@ -79,4 +89,4 @@ def local_detuning_start_and_end_values(cls, values): raise ValueError( f"The values of the shifting field magnitude time series at the first and last time points are {start_value}, {end_value}; they both must be both 0." ) - return values \ No newline at end of file + return values \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py index 4f8aa666..da2bed00 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py @@ -35,6 +35,9 @@ def magnitude_pattern_is_not_uniform(cls, values): @root_validator(pre=True, skip_on_failure=True) def magnitude_pattern_within_bounds(cls, values): + if not capabilities.MAGNITUDE_PATTERN_VALUE_MIN or \ + not capabilities.MAGNITUDE_PATTERN_VALUE_MAX: + return values magnitude = values["magnitude"] capabilities = values["capabilities"] pattern = magnitude["pattern"] @@ -51,6 +54,9 @@ def magnitude_pattern_within_bounds(cls, values): @root_validator(pre=True, skip_on_failure=True) def magnitude_values_within_range(cls, values): + if not capabilities.LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN or \ + not capabilities.LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX: + return values magnitude = values["magnitude"] capabilities = values["capabilities"] magnitude_values = magnitude["time_series"]["values"] From 315e57820fe601afa4468b2bdf273da23ad11334 Mon Sep 17 00:00:00 2001 From: Nagji Date: Thu, 18 Jul 2024 14:09:52 -0700 Subject: [PATCH 03/10] fix: Remove bad method in DeviceAtomArrangementValidator, fix local detuning check in DeviceHamiltonianValidator. --- .../device_atom_arrangement.py | 14 +++------- .../device_capabilities_constants.py | 6 ++++- .../device_validators/device_hamiltonian.py | 27 +++++++++++++++++++ .../device_validators/device_ir_validator.py | 4 +-- 4 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index 386dd72d..350ec1e7 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -5,6 +5,9 @@ PhysicalField ) from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants +from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( + validate_value_precision +) from pydantic.v1.class_validators import root_validator from decimal import Decimal from typing import Tuple @@ -69,7 +72,7 @@ def sites_in_rows(cls, values): capabilities = values["capabilities"] sorted_sites = sorted(sites, key=lambda xy: xy[1]) min_allowed_distance = capabilities.MIN_ROW_DISTANCE - if values["feature_access"]: + if capabilities.LOCAL_RYDBERG_CAPABILITIES: min_allowed_distance = Decimal("0.000002") for s1, s2 in zip(sorted_sites[:-1], sorted_sites[1:]): row_distance = _y_distance(s1, s2) @@ -94,12 +97,3 @@ def atom_number_limit(cls, values): ) return values - @root_validator(pre=True, skip_on_failure=True) - def phase_value_precision_is_correct(cls, values): - phase = values["phase"] - capabilities = values["capabilities"] - phase_obj = PhysicalField.parse_obj(phase) - validate_value_precision( - phase_obj.time_series.values, capabilities.GLOBAL_PHASE_VALUE_PRECISION, "phase" - ) - return values \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py index 19b09fa8..b0519a1e 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py @@ -2,7 +2,6 @@ CapabilitiesConstants ) from decimal import Decimal -from pydantic import PositiveInt from typing import Optional @@ -10,12 +9,17 @@ class DeviceCapabilitiesConstants(CapabilitiesConstants): MAX_SITES: int SITE_PRECISION: Decimal MAX_FILLED_SITES: int + MIN_ROW_DISTANCE: Decimal GLOBAL_TIME_PRECISION: Decimal GLOBAL_AMPLITUDE_VALUE_PRECISION: Decimal GLOBAL_AMPLITUDE_SLOPE_MAX: Decimal + GLOBAL_MIN_TIME_SEPARATION: Decimal GLOBAL_DETUNING_VALUE_PRECISION: Decimal GLOBAL_DETUNING_SLOPE_MAX: Decimal + GLOBAL_PHASE_VALUE_MIN: Decimal + GLOBAL_PHASE_VALUE_MAX: Decimal + GLOBAL_PHASE_VALUE_PRECISION: Decimal LOCAL_RYDBERG_CAPABILITIES: bool = False LOCAL_MAGNITUDE_SLOPE_MAX: Optional[Decimal] diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py new file mode 100644 index 00000000..82fc928f --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py @@ -0,0 +1,27 @@ +from pydantic.v1.class_validators import root_validator +from braket.analog_hamiltonian_simulator.rydberg.validators.hamiltonian import \ + HamiltonianValidator +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_capabilities_constants import DeviceCapabilitiesConstants + +class DeviceHamiltonianValidator(HamiltonianValidator): + LOCAL_RYDBERG_CAPABILITIES: bool = False + + @root_validator(pre=True, skip_on_failure=True) + def max_zero_local_detuning(cls, values): + LOCAL_RYDBERG_CAPABILITIES = values["LOCAL_RYDBERG_CAPABILITIES"] + local_detuning = values.get("localDetuning", []) + if not LOCAL_RYDBERG_CAPABILITIES: + if len(local_detuning) > 1: + raise ValueError( + f"At most one local detuning specification can be provided;\ + {len(local_detuning)} are given." + ) + else: + if len(local_detuning) > 0: + raise ValueError( + f"Local detuning cannot be specified; \ +{len(local_detuning)} are given. Specifying local \ +detuning is an experimental capability, use Braket Direct to request access." + ) + return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py index 009ffac3..0154a753 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py @@ -22,7 +22,7 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( DeviceDrivingFieldValidator ) -from braket.analog_hamiltonian_simulator.rydberg.validators.hamiltonian import HamiltonianValidator +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_hamiltonian import DeviceHamiltonianValidator from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( DeviceLocalDetuningValidator ) @@ -45,7 +45,7 @@ def validate_program(program: Program, device_capabilities: DeviceCapabilitiesCo ProgramValidator(capabilities=device_capabilities, **program.dict()) DeviceAtomArrangementValidator(capabilities=device_capabilities, **program.setup.ahs_register.dict()) - HamiltonianValidator(**program.hamiltonian.dict()) + DeviceHamiltonianValidator(LOCAL_RYDBERG_CAPABILITIES=device_capabilities.LOCAL_RYDBERG_CAPABILITIES, **program.hamiltonian.dict()) for d_fields in program.hamiltonian.drivingFields: DeviceDrivingFieldValidator(capabilities=device_capabilities, **d_fields.dict()) amplitude = d_fields.amplitude From c6741d9cdd5ab5b7fe5e6971b433bcee5fa5bcc1 Mon Sep 17 00:00:00 2001 From: Nagji Date: Fri, 19 Jul 2024 12:59:47 -0700 Subject: [PATCH 04/10] test: Add tests for device driving field and atom arrangment validators --- .../device_atom_arrangement.py | 9 - .../device_validators/device_driving_field.py | 12 - .../device_validators/device_ir_validator.py | 1 + .../validators/device_validators/conftest.py | 61 +++++ .../test_device_atom_arrangement.py | 153 ++++++++++++ .../test_device_driving_field.py | 219 ++++++++++++++++++ 6 files changed, 434 insertions(+), 21 deletions(-) create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index 350ec1e7..36108fed 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -28,15 +28,6 @@ def sites_not_empty(cls, values): if not sites: raise ValueError("Sites can not be empty.") return values - - - # Each site has two coordinates (minItems=maxItems=2) - @root_validator(pre=True, skip_on_failure=True) - def filling_not_empty(cls, values): - filling = values["filling"] - if not filling: - raise ValueError("Filling can not be empty.") - return values # The maximum allowable precision in the coordinates is SITE_PRECISION diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py index 4aca9dff..db5e01ac 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py @@ -153,18 +153,6 @@ def detuning_timepoint_not_too_close(cls, values): detuning["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "detuning" ) return values - - @root_validator(pre=True, skip_on_failure=True) - def detuning_value_precision_is_correct(cls, values): - detuning = values["detuning"] - capabilities = values["capabilities"] - detuning_obj = PhysicalField.parse_obj(detuning) - validate_value_precision( - detuning_obj.time_series.values, - capabilities.GLOBAL_DETUNING_VALUE_PRECISION, - "detuning", - ) - return values @root_validator(pre=True, skip_on_failure=True) def detuning_slopes_not_too_steep(cls, values): diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py index 0154a753..2e0f4dcd 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py @@ -51,6 +51,7 @@ def validate_program(program: Program, device_capabilities: DeviceCapabilitiesCo amplitude = d_fields.amplitude phase = d_fields.phase detuning = d_fields.detuning + PhysicalFieldValidator(**amplitude.dict()) TimeSeriesValidator(capabilities=device_capabilities, **amplitude.time_series.dict()) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py new file mode 100644 index 00000000..7d51c6a1 --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py @@ -0,0 +1,61 @@ +import pytest +from decimal import Decimal +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_capabilities_constants import DeviceCapabilitiesConstants + +@pytest.fixture +def non_local_capabilities_constants(): + capabilities_dict = { + 'BOUNDING_BOX_SIZE_X': Decimal('0.000075'), + 'BOUNDING_BOX_SIZE_Y': Decimal('0.000076'), + 'DIMENSIONS': 2, + 'GLOBAL_AMPLITUDE_SLOPE_MAX': Decimal('250000000000000'), + 'GLOBAL_AMPLITUDE_VALUE_MAX': Decimal('15800000.0'), + 'GLOBAL_AMPLITUDE_VALUE_MIN': Decimal('0.0'), + 'GLOBAL_AMPLITUDE_VALUE_PRECISION': Decimal('400.0'), + 'GLOBAL_DETUNING_SLOPE_MAX': Decimal('250000000000000'), + 'GLOBAL_DETUNING_VALUE_MAX': Decimal('125000000.0'), + 'GLOBAL_DETUNING_VALUE_MIN': Decimal('-125000000.0'), + 'GLOBAL_DETUNING_VALUE_PRECISION': Decimal('0.2'), + 'GLOBAL_MIN_TIME_SEPARATION': Decimal('1E-8'), + 'GLOBAL_PHASE_VALUE_MAX': Decimal('99.0'), + 'GLOBAL_PHASE_VALUE_MIN': Decimal('-99.0'), + 'GLOBAL_PHASE_VALUE_PRECISION': Decimal('5E-7'), + 'GLOBAL_TIME_PRECISION': Decimal('1E-9'), + 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX': None, + 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN': None, + 'LOCAL_MAGNITUDE_SLOPE_MAX': None, + 'LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES': None, + 'LOCAL_MIN_TIME_SEPARATION': None, + 'LOCAL_RYDBERG_CAPABILITIES': False, + 'LOCAL_TIME_PRECISION': None, + 'MAGNITUDE_PATTERN_VALUE_MAX': None, + 'MAGNITUDE_PATTERN_VALUE_MIN': None, + 'MAX_FILLED_SITES': 4, + 'MAX_NET_DETUNING': None, + 'MAX_SITES': 8, + 'MAX_TIME': Decimal('0.000004'), + 'MIN_DISTANCE': Decimal('0.000004'), + 'MIN_ROW_DISTANCE': Decimal('0.000004'), + 'SITE_PRECISION': Decimal('1E-7') + } + return DeviceCapabilitiesConstants(**capabilities_dict) + + +@pytest.fixture +def capabilities_with_local_rydberg(non_local_capabilities_constants): + local_rydberg_constants = { + 'LOCAL_RYDBERG_CAPABILITIES': True, + 'LOCAL_TIME_PRECISION': Decimal('1e-9'), + 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX': Decimal('125000000.0'), + 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN': Decimal('0.0'), + 'LOCAL_MAGNITUDE_SLOPE_MAX': Decimal('1256600000000000.0'), + 'LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES': Decimal('5e-06'), + 'LOCAL_MIN_TIME_SEPARATION': Decimal('1E-8'), + 'LOCAL_MAX_NONZERO_PATTERN_VALUES': 200, + 'MAGNITUDE_PATTERN_VALUE_MAX': Decimal('1.0'), + 'MAGNITUDE_PATTERN_VALUE_MIN': Decimal('0.0'), + } + capabilities_dict = non_local_capabilities_constants.dict() + capabilities_dict.update(local_rydberg_constants) + return DeviceCapabilitiesConstants(**capabilities_dict) \ No newline at end of file diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py new file mode 100644 index 00000000..49e011b2 --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py @@ -0,0 +1,153 @@ +import pytest +from braket.analog_hamiltonian_simulator.rydberg.constants import capabilities_constants +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_capabilities_constants import DeviceCapabilitiesConstants +from decimal import Decimal + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_atom_arrangement import DeviceAtomArrangementValidator + +from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement \ + import AtomArrangement + +from pydantic.v1.error_wrappers import ValidationError + + +@pytest.fixture +def mock_atom_arrangement_data(): + data = { + "sites": [], + "filling": [], + } + return AtomArrangement.parse_obj(data).dict() + + +@pytest.mark.parametrize( + "sites, filling, error_message", + [ + ( + [], + [], + "Sites can not be empty.", + ), + ( + [], + [1, 0, 1, 0], + "Filling length (4) does not match sites length (0)", + ), + ( + [ + [Decimal("0.0"), Decimal("0.0")], + [Decimal("0.0"), Decimal("4e-6")], + [Decimal("5e-6"), Decimal("0.0")], + [Decimal("5e-6"), Decimal("4e-6")], + ], + [], + "Filling length (0) does not match sites length (4)", + ), + ], +) +def test_atom_arrangement_sites_or_fillings_empty( + sites, filling, error_message, mock_atom_arrangement_data, + non_local_capabilities_constants +): + mock_atom_arrangement_data["sites"] = sites + mock_atom_arrangement_data["filling"] = filling + _assert_atom_arrangement(mock_atom_arrangement_data, error_message, non_local_capabilities_constants) + + +@pytest.mark.parametrize( + "sites, filling ,error_message", + [ + ( + [[1.1e-6, 1.1e-6], [2.2e-6, 7.31e-6]], + [1, 0], + "Coordinates 1([2.2e-06, 7.31e-06]) is defined with too high precision; they must be multiples of 1E-7 meters", + ), + ( + [[3.201e-6, 0.0], [0.00, 4.1e-6], [-1.101e-6, 8.11e-6]], + [1, 0, 1], + "Coordinates 0([3.201e-06, 0.0]) is defined with too high precision; they must be multiples of 1E-7 meters", + ), + ], +) +# Rule: Lattice coordinates have a maximum precision of lattice.geometry.position_resolution +def test_atom_arrangement_sites_defined_with_right_precision( + sites, filling, error_message, mock_atom_arrangement_data, non_local_capabilities_constants +): + mock_atom_arrangement_data["sites"] = sites + mock_atom_arrangement_data["filling"] = filling + _assert_atom_arrangement( + mock_atom_arrangement_data, error_message, non_local_capabilities_constants + ) + + + + +def _assert_atom_arrangement( + data, error_message, device_capabilities_constants +): + with pytest.raises(ValidationError) as e: + DeviceAtomArrangementValidator( + capabilities=device_capabilities_constants, **data + ) + assert error_message in str(e.value) + + + +def test_atom_arrangement_sites_not_too_many( + mock_atom_arrangement_data, non_local_capabilities_constants +): + sites = [[0.0, 0.0]] * (non_local_capabilities_constants.MAX_SITES + 1) + filling = [0] * (non_local_capabilities_constants.MAX_SITES + 1) + mock_atom_arrangement_data["sites"] = sites + mock_atom_arrangement_data["filling"] = filling + error_message = "There are too many sites (9); there must be at most 8 sites" + _assert_atom_arrangement( + mock_atom_arrangement_data, error_message, non_local_capabilities_constants + ) + + +@pytest.mark.parametrize( + "sites, filling,error_message", + [ + ( + [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("2.4e-6")]], + [0, 1], + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), Decimal('0.0000024')] have y-separation (0.0000024). It must either be exactly zero or not smaller than 0.000004 meters", + ), + ( + [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("1.4e-6")]], + [0, 1], + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), Decimal('0.0000014')] have y-separation (0.0000014). It must either be exactly zero or not smaller than 0.000004 meters", + ), + ], +) +# Rule: All sites in the lattice must be separated vertically by at least lattice.geometry.spacing_vertical_min +def test_atom_arrangement_sites_in_rows( + sites, + filling, + error_message, + mock_atom_arrangement_data, + non_local_capabilities_constants, +): + mock_atom_arrangement_data["sites"] = sites + mock_atom_arrangement_data["filling"] = filling + _assert_atom_arrangement( + mock_atom_arrangement_data, + error_message, + non_local_capabilities_constants, + ) + + +def test_atom_arrangement_filling_atom_number_limit( + mock_atom_arrangement_data, non_local_capabilities_constants +): + filling = [1] * (non_local_capabilities_constants.MAX_FILLED_SITES + 1) + mock_atom_arrangement_data["filling"] = filling + mock_atom_arrangement_data["sites"] = [[0, 0], [0, 0.00004], [0, 0.00005], [0.00005, 0.00004], [0.00005, 0]] + error_message = "Filling has 5 '1' entries; is must have not more than 4" + _assert_atom_arrangement( + mock_atom_arrangement_data, error_message, non_local_capabilities_constants + ) + \ No newline at end of file diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py new file mode 100644 index 00000000..4070e7cc --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py @@ -0,0 +1,219 @@ +import pytest +from pydantic.v1.error_wrappers import ValidationError +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_driving_field import DeviceDrivingFieldValidator +from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field \ + import DrivingField + + + +@pytest.fixture +def mock_driving_field_data(): + data = { + "amplitude": { + "pattern": "uniform", + "time_series": { + "times": [], + "values": [], + }, + }, + "phase": { + "pattern": "uniform", + "time_series": { + "times": [], + "values": [], + }, + }, + "detuning": { + "pattern": "uniform", + "time_series": { + "times": [], + "values": [], + }, + }, + } + return DrivingField.parse_obj(data).dict() + + +@pytest.mark.parametrize( + "times, field_name, error_message", + [ + ( + [0.0, 12.1e-9], + "amplitude", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9], + "phase", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9], + "detuning", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 4e-6], + "amplitude", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 4e-6], + "phase", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 4e-6], + "detuning", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 22.1e-9], + "amplitude", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 22.1e-9], + "phase", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 12.1e-9, 22.1e-9], + "detuning", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 22.1e-9, 12.1e-9], + "amplitude", + "time point 1 (2.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 22.1e-9, 12.1e-9], + "phase", + "time point 1 (2.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ( + [0.0, 22.1e-9, 12.1e-9], + "detuning", + "time point 1 (2.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + ), + ], +) +# Rule: The times for any component of the effective Hamiltonian have a maximum precision of rydberg.global.time_resolution +def test_driving_field_time_precision_is_correct( + times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants +): + mock_driving_field_data[field_name]["time_series"]["times"] = times + _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + +@pytest.mark.parametrize( + "times, field_name, error_message", + [ + ( + [0.0, 9e-9, 25e-9], + "amplitude", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ( + [0.0, 9e-9, 25e-9], + "phase", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ( + [0.0, 9e-9, 25e-9], + "detuning", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ( + [0.0, 9e-9, 25e-9, 30e-9], + "amplitude", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ( + [0.0, 9e-9, 25e-9, 30e-9], + "phase", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ( + [0.0, 9e-9, 25e-9, 30e-9], + "detuning", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + ), + ], +) +# Rule: The times for any component of the effective Hamiltonian must be spaced by at least rydberg.global.time_delta_min +def test_driving_field_timepoint_not_too_close( + times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants +): + mock_driving_field_data[field_name]["time_series"]["times"] = times + _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + + +@pytest.mark.parametrize( + "values, field_name, error_message", + [ + ( + [2.5e7, 2.5e7, 2.5e7, 0.0], + "amplitude", + "The values of the Rabi frequency at the first and last time points are 25000000.0, 0.0; they both must be both 0.", + ), + ( + [0.0, 2.5e7, 2.5e7, 2.5e7], + "amplitude", + "The values of the Rabi frequency at the first and last time points are 0.0, 25000000.0; they both must be both 0.", + ), + ( + [2.5e7, 2.5e7, 2.5e7, 2.5e7], + "amplitude", + "The values of the Rabi frequency at the first and last time points are 25000000.0, 25000000.0; they both must be both 0.", + ), + ], +) +# Rule: The global Rydberg Rabi frequency amplitude must start and end at 0. +def test_driving_field_amplitude_start_and_end_values( + values, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants +): + mock_driving_field_data[field_name]["time_series"]["values"] = values + _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + + +@pytest.mark.parametrize( + "values, times, field_name, error_message", + [ + ( + [0.0, 2.5e7, 0.0], + [0.0, 0.01e-6, 2.0e-6], + "amplitude", + "For the amplitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", + ), + ( + [0.0, 2.5e7, 2.5e7, 0.0], + [0.0, 0.01e-6, 3.2e-6, 3.21e-6], + "amplitude", + "For the amplitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", + ), + ( + [0.0, 2.5e7, 2.5e7, 0.0], + [0.0, 0.01e-6, 3.2e-6, 3.21e-6], + "detuning", + "For the detuning field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", + ), + ] +) +def test_driving_field_slopes_not_too_steep( + values, times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants +): + mock_driving_field_data[field_name]["time_series"]["values"] = values + mock_driving_field_data[field_name]["time_series"]["times"] = times + _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + +def test_phase_values_start_with_0(mock_driving_field_data, non_local_capabilities_constants): + mock_driving_field_data["phase"]["time_series"]["values"] = [0.1, 2.5e7] + error_message = "The first value of of driving field phase is 0.1; it must be 0." + _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + +def _assert_driving_field(data, error_message, device_capabilities_constants): + with pytest.raises(ValidationError) as e: + DeviceDrivingFieldValidator(capabilities=device_capabilities_constants, **data) + assert error_message in str(e.value) \ No newline at end of file From c00563c2c411bb9ea41dbe80cc669af94c50720c Mon Sep 17 00:00:00 2001 From: Nagji Date: Sat, 20 Jul 2024 16:11:18 -0700 Subject: [PATCH 05/10] test: Get complete test coverage on device validators --- a.txt | 1 + .../device_atom_arrangement.py | 3 - .../device_capabilities_constants.py | 3 +- .../device_validators/device_hamiltonian.py | 12 +- .../device_local_detuning.py | 13 +- .../validators/field_validator_util.py | 13 +- .../rydberg/validators/local_detuning.py | 6 - .../test_device_atom_arrangement.py | 22 ++- .../test_device_driving_field.py | 81 ++++++++-- .../test_device_hamiltonian.py | 72 +++++++++ .../test_device_local_detuning.py | 146 ++++++++++++++++++ 11 files changed, 322 insertions(+), 50 deletions(-) create mode 100644 a.txt create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py diff --git a/a.txt b/a.txt new file mode 100644 index 00000000..2d87c7bc --- /dev/null +++ b/a.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index 36108fed..d57822d3 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -5,9 +5,6 @@ PhysicalField ) from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants -from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( - validate_value_precision -) from pydantic.v1.class_validators import root_validator from decimal import Decimal from typing import Tuple diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py index b0519a1e..cc16f9f4 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py @@ -28,7 +28,8 @@ class DeviceCapabilitiesConstants(CapabilitiesConstants): LOCAL_MIN_TIME_SEPARATION: Optional[Decimal] LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN: Optional[Decimal] LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX: Optional[Decimal] - + LOCAL_MAX_NONZERO_PATTERN_VALUES: Optional[Decimal] + MAGNITUDE_PATTERN_VALUE_MIN: Optional[Decimal] MAGNITUDE_PATTERN_VALUE_MAX: Optional[Decimal] MAX_NET_DETUNING: Optional[Decimal] diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py index 82fc928f..b619a7b9 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py @@ -12,16 +12,10 @@ def max_zero_local_detuning(cls, values): LOCAL_RYDBERG_CAPABILITIES = values["LOCAL_RYDBERG_CAPABILITIES"] local_detuning = values.get("localDetuning", []) if not LOCAL_RYDBERG_CAPABILITIES: - if len(local_detuning) > 1: + if len(local_detuning) > 0: raise ValueError( - f"At most one local detuning specification can be provided;\ - {len(local_detuning)} are given." - ) - else: - if len(local_detuning) > 0: - raise ValueError( - f"Local detuning cannot be specified; \ + f"Local detuning cannot be specified; \ {len(local_detuning)} are given. Specifying local \ detuning is an experimental capability, use Braket Direct to request access." - ) + ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py index 8e155a16..95566447 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py @@ -4,15 +4,17 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( PhysicalField ) -from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( - validate_time_precision, - validate_max_absolute_slope, - validate_time_separation -) from pydantic.v1.class_validators import root_validator from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ device_capabilities_constants import DeviceCapabilitiesConstants +from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( + validate_time_precision, + validate_max_absolute_slope, + validate_time_separation +) + +from pprint import pprint class DeviceLocalDetuningValidator(LocalDetuningValidator): capabilities: DeviceCapabilitiesConstants @@ -25,6 +27,7 @@ def check_local_rydberg_capabilities(cls, values): "Local Rydberg capabilities information has not been \ provided for local detuning." ) + return values # Rule: The number of locally-addressed sites must not exceed rydberg.local.number_local_detuning_sites diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py index 4525fee2..f2057dcc 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py @@ -104,15 +104,6 @@ def validate_net_detuning_with_warning( # Return immediately if there is an atom has net detuning # exceeding MAX_NET_DETUNING at a time point return program - - -def validate_pattern_precision(values: List[Decimal], max_precision: Decimal, name: str): - # Raise ValueError if at any item in the values is beyond the max allowable precision - for idx, v in enumerate(values): - if v % max_precision != 0: - raise ValueError( - f"Value {idx} ({v}) in {name} pattern is defined with too many digits; it must be an integer mutiple of {max_precision}" - ) # Two time points cannot be too close, assuming the time points are sorted ascendingly def validate_time_separation(times: List[Decimal], min_time_separation: Decimal, name: str): @@ -129,7 +120,7 @@ def validate_value_precision(values: List[Decimal], max_precision: Decimal, name for idx, v in enumerate(values): if v % max_precision != 0: raise ValueError( - f"Value {idx} ({v}) in {name} time_series is defined with too many digits; it must be an integer mutiple of {max_precision}" + f"Value {idx} ({v}) in {name} time_series is defined with too many digits; it must be an integer multiple of {max_precision}" ) def validate_max_absolute_slope( @@ -147,5 +138,5 @@ def validate_time_precision(times: List[Decimal], time_precision: Decimal, name: for idx, t in enumerate(times): if t % time_precision != 0: raise ValueError( - f"time point {idx} ({t}) of {name} time_series is defined with too many digits; it must be an integer multple of {time_precision}" + f"time point {idx} ({t}) of {name} time_series is defined with too many digits; it must be an integer multiple of {time_precision}" ) \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py index da2bed00..4f8aa666 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/local_detuning.py @@ -35,9 +35,6 @@ def magnitude_pattern_is_not_uniform(cls, values): @root_validator(pre=True, skip_on_failure=True) def magnitude_pattern_within_bounds(cls, values): - if not capabilities.MAGNITUDE_PATTERN_VALUE_MIN or \ - not capabilities.MAGNITUDE_PATTERN_VALUE_MAX: - return values magnitude = values["magnitude"] capabilities = values["capabilities"] pattern = magnitude["pattern"] @@ -54,9 +51,6 @@ def magnitude_pattern_within_bounds(cls, values): @root_validator(pre=True, skip_on_failure=True) def magnitude_values_within_range(cls, values): - if not capabilities.LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN or \ - not capabilities.LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX: - return values magnitude = values["magnitude"] capabilities = values["capabilities"] magnitude_values = magnitude["time_series"]["values"] diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py index 49e011b2..4fdfcf0b 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py @@ -12,7 +12,14 @@ from pydantic.v1.error_wrappers import ValidationError - +@pytest.fixture +def atom_arrangement_data(): + return { + "sites": [[0, 0], [0, 5e-6], [5e-6, 0], [5e-6, 10e-6]], + "filling": [1, 0, 1, 0], + } + + @pytest.fixture def mock_atom_arrangement_data(): data = { @@ -49,11 +56,20 @@ def mock_atom_arrangement_data(): ) def test_atom_arrangement_sites_or_fillings_empty( sites, filling, error_message, mock_atom_arrangement_data, - non_local_capabilities_constants + capabilities_with_local_rydberg ): mock_atom_arrangement_data["sites"] = sites mock_atom_arrangement_data["filling"] = filling - _assert_atom_arrangement(mock_atom_arrangement_data, error_message, non_local_capabilities_constants) + _assert_atom_arrangement(mock_atom_arrangement_data, error_message, capabilities_with_local_rydberg) + + +def test_valid_atom_array(atom_arrangement_data, capabilities_with_local_rydberg): + try: + DeviceAtomArrangementValidator( + capabilities=capabilities_with_local_rydberg, **atom_arrangement_data + ) + except ValidationError as e: + pytest.fail(f"Validate test is failing : {str(e)}") @pytest.mark.parametrize( diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py index 4070e7cc..fc5a67e9 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py @@ -6,6 +6,31 @@ import DrivingField +@pytest.fixture +def driving_field_data(): + return { + "amplitude": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [0, 12566400.0, 12566400.0, 0], + }, + }, + "phase": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [0, 0, -16.0832, -16.0832], + }, + }, + "detuning": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [-125000000, -125000000, 125000000, 125000000], + }, + }, + } @pytest.fixture def mock_driving_field_data(): @@ -35,68 +60,75 @@ def mock_driving_field_data(): return DrivingField.parse_obj(data).dict() +def test_device_driving_field(driving_field_data, non_local_capabilities_constants): + try: + DeviceDrivingFieldValidator(capabilities=non_local_capabilities_constants, **driving_field_data) + except ValidationError as e: + pytest.fail(f"Validate test is failing : {str(e)}") + + @pytest.mark.parametrize( "times, field_name, error_message", [ ( [0.0, 12.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "amplitude", - "time point 1 (2.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (2.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "phase", - "time point 1 (2.21E-8) of phase time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (2.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "detuning", - "time point 1 (2.21E-8) of detuning time_series is defined with too many digits; it must be an integer multple of 1E-9", + "time point 1 (2.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", ), ], ) @@ -107,6 +139,31 @@ def test_driving_field_time_precision_is_correct( mock_driving_field_data[field_name]["time_series"]["times"] = times _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) +def test_driving_field_no_detuning(mock_driving_field_data, non_local_capabilities_constants): + mock_driving_field_data["detuning"]["time_series"]["times"].clear() + mock_driving_field_data["detuning"]["time_series"]["values"].clear() + try: + DeviceDrivingFieldValidator(capabilities=non_local_capabilities_constants, **mock_driving_field_data) + except ValidationError as e: + pytest.fail(f"Validate test is failing : {str(e)}") + + +@pytest.mark.parametrize( + "values, field_name, error_message", + [ + ( + [0.0, 22.1e-9, 12,1e-9, 0.0], + "amplitude", + "Value 1 (2.21E-8) in amplitude time_series is defined with too many digits; it must be an integer multiple of 400.0", + ) + ] +) +def test_driving_field_value_precision_is_correct( + values, field_name, error_message, driving_field_data, non_local_capabilities_constants +): + driving_field_data[field_name]["time_series"]["values"] = values + _assert_driving_field(driving_field_data, error_message, non_local_capabilities_constants) + @pytest.mark.parametrize( "times, field_name, error_message", [ diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py new file mode 100644 index 00000000..5b756609 --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py @@ -0,0 +1,72 @@ +import pytest +from pydantic.v1.error_wrappers import ValidationError +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators \ + .device_hamiltonian import DeviceHamiltonianValidator + + +@pytest.fixture +def hamiltonian_data(): + return { + "drivingFields": [ + { + "amplitude": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [0, 12566400.0, 12566400.0, 0], + }, + }, + "phase": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [0, 0, -16.0832, -16.0832], + }, + }, + "detuning": { + "pattern": "uniform", + "time_series": { + "times": [0, 1e-07, 3.9e-06, 4e-06], + "values": [-125000000, -125000000, 125000000, 125000000], + }, + }, + } + ], + "localDetuning": [ + { + "magnitude": { + "time_series": {"times": [0, 4e-6], "values": [0, 0]}, + "pattern": [0.0, 1.0, 0.5, 0.0, 1.0], + } + } + ], + } + +def test_hamiltonian(hamiltonian_data): + try: + DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=True) + except ValidationError as e: + pytest.fail(f"Validate test is failing : {str(e)}") + +@pytest.mark.parametrize( + "local_rydberg_exists", + [ + (True), + (False) + ] +) +def test_hamiltonian_no_detuning(local_rydberg_exists, hamiltonian_data): + hamiltonian_data["localDetuning"].clear() + try: + DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=local_rydberg_exists) + except ValidationError as e: + pytest.fail(f"Validate test is failing : {str(e)}") + +def test_no_local_rydberg_capabilities(hamiltonian_data): + error_message = "Local detuning cannot be specified; \ +1 are given. Specifying local \ +detuning is an experimental capability, use Braket Direct to request access." + with pytest.raises(ValidationError) as e: + DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=False) + assert error_message in str(e.value) + diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py new file mode 100644 index 00000000..5a33c566 --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py @@ -0,0 +1,146 @@ +import pytest +from pydantic.v1.error_wrappers import ValidationError +from braket.ir.ahs.local_detuning import LocalDetuning +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ + device_local_detuning import DeviceLocalDetuningValidator + + + +@pytest.fixture +def local_detuning_data(): + return { + "magnitude": { + "time_series": {"times": [0, 1e-07], "values": [0, 0]}, + "pattern": [0.0, 0.1, 0.1, 0.0, 0.1], + } + } + + +@pytest.fixture +def mock_local_detuning_data(): + data = { + "magnitude": { + "pattern": [], + "time_series": { + "times": [], + "values": [], + }, + } + } + return LocalDetuning.parse_obj(data).dict() + + + +def test_valid_detuning(local_detuning_data, capabilities_with_local_rydberg): + try: + DeviceLocalDetuningValidator(capabilities=capabilities_with_local_rydberg, **local_detuning_data) + except ValidationError as e: + pytest.fail(f"Validate test is failing: {str(e.value)}") + +def test_validation_no_time_series(mock_local_detuning_data, capabilities_with_local_rydberg): + mock_local_detuning_data["magnitude"]["time_series"]["times"].clear() + mock_local_detuning_data["magnitude"]["time_series"]["values"].clear() + + try: + DeviceLocalDetuningValidator(capabilities=capabilities_with_local_rydberg, **mock_local_detuning_data) + except ValidationError as e: + pytest.fail(f"Validate test is failing: {str(e.value)}") + +def test_validation_no_detuning_data(mock_local_detuning_data, non_local_capabilities_constants): + error_message = "Local Rydberg capabilities information has not been \ + provided for local detuning." + non_local_capabilities_constants.LOCAL_RYDBERG_CAPABILITIES = False + with pytest.raises(ValueError) as e: + DeviceLocalDetuningValidator(capabilities=non_local_capabilities_constants, **mock_local_detuning_data) + assert error_message in str(e.value) + + + +def test_shifting_field_magnitude_pattern_have_not_too_many_nonzeros( + mock_local_detuning_data, capabilities_with_local_rydberg +): + pattern = [0.1] * 257 + mock_local_detuning_data["magnitude"]["pattern"] = pattern + error_message = ( + "Number of nonzero magnitude pattern values is 257; it must not be more than 200" + ) + _assert_local_detuning(mock_local_detuning_data, error_message, capabilities_with_local_rydberg) + + +@pytest.mark.parametrize( + "values, times, error_message", + [ + ( + [0.0, 2.5e7, 0.0], + [0.0, 0.01e-6, 2.0e-6], + "For the magnitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 1256600000000000.0", + ), + ( + [0.0, 2.5e7, 2.5e7, 0.0], + [0.0, 0.01e-6, 3.2e-6, 3.21e-6], + "For the magnitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 1256600000000000.0", + ), + ], +) +def test_local_detuning_slopes_not_too_steep( + values, times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg +): + mock_local_detuning_data["magnitude"]["time_series"]["values"] = values + mock_local_detuning_data["magnitude"]["time_series"]["times"] = times + _assert_local_detuning(mock_local_detuning_data, error_message, capabilities_with_local_rydberg) + + +@pytest.mark.parametrize( + "times, error_message", + [ + ( + [0.0, 12.1e-9], + "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + ), + ( + [0.0, 12.1e-9, 4e-6], + "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + ), + ( + [0.0, 12.1e-9, 22.1e-9], + "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + ), + ( + [0.0, 22.1e-9, 12.1e-9], + "time point 1 (2.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + ), + ], +) +# Rule: The times for any component of the effective Hamiltonian have a maximum precision of rydberg.global.time_resolution +def test_shifting_field_magnitude_time_precision_is_correct( + times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg +): + mock_local_detuning_data["magnitude"]["time_series"]["times"] = times + _assert_local_detuning(mock_local_detuning_data, error_message, capabilities_with_local_rydberg) + + +@pytest.mark.parametrize( + "times, error_message", + [ + ( + [0.0, 1.0, 2.0], + "The values of the shifting field magnitude time series at the first and last time points are 0.0, 2.0; they both must be both 0." + ), + ( + [0.2, 1.0, 0], + "The values of the shifting field magnitude time series at the first and last time points are 0.2, 0; they both must be both 0." + ), + ( + [0.0, 0.0, 1e-5], + "The values of the shifting field magnitude time series at the first and last time points are 0.0, 1e-05; they both must be both 0." + ), + ] +) +def test_shifting_start_and_end_are_zero(times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg): + mock_local_detuning_data["magnitude"]["time_series"]["values"] = times + _assert_local_detuning(mock_local_detuning_data, error_message, capabilities_with_local_rydberg) + +def _assert_local_detuning(data, error_message, device_capabilities_constants): + with pytest.raises(ValidationError) as e: + DeviceLocalDetuningValidator(capabilities=device_capabilities_constants, **data) + assert error_message in str(e.value) \ No newline at end of file From 24ebf9a29e06106f3756cea0ae4a54804e1b58fb Mon Sep 17 00:00:00 2001 From: Nagji Date: Sun, 21 Jul 2024 12:08:59 -0700 Subject: [PATCH 06/10] feat: Add __init__.py to device validators --- .../validators/device_validators/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py new file mode 100644 index 00000000..3cadf944 --- /dev/null +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py @@ -0,0 +1,15 @@ +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( # noqa: F401 + DeviceAtomArrangementValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( # noqa: F401 + DeviceCapabilitiesConstants, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( # noqa: F401 + DeviceDrivingFieldValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_hamiltonian import ( # noqa: F401 + DeviceHamiltonianValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( # noqa: F401 + DeviceLocalDetuningValidator, +) From 079f1b4fd4828b0d5b2bd9a0b9cd071816d34e69 Mon Sep 17 00:00:00 2001 From: Nagji Date: Sun, 21 Jul 2024 12:31:26 -0700 Subject: [PATCH 07/10] change: Run linters and make enforce style rules --- .../validators/device_validators/__init__.py | 10 +- .../device_atom_arrangement.py | 43 +++--- .../device_capabilities_constants.py | 12 +- .../device_validators/device_driving_field.py | 53 ++++--- .../device_validators/device_hamiltonian.py | 15 +- .../device_validators/device_ir_validator.py | 27 ++-- .../device_local_detuning.py | 54 +++---- .../validators/field_validator_util.py | 29 ++-- .../validators/device_validators/conftest.py | 98 ++++++------ .../test_device_atom_arrangement.py | 79 +++++----- .../test_device_driving_field.py | 141 ++++++++++++------ .../test_device_hamiltonian.py | 28 ++-- .../test_device_local_detuning.py | 86 +++++++---- 13 files changed, 380 insertions(+), 295 deletions(-) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py index 3cadf944..cb068b2c 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py @@ -1,15 +1,15 @@ -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( # noqa: F401 +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( # noqa: E501 F401 DeviceAtomArrangementValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( # noqa: F401 +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( # noqa: E501 F401 DeviceCapabilitiesConstants, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( # noqa: F401 +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( # noqa: E501 F401 DeviceDrivingFieldValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_hamiltonian import ( # noqa: F401 +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_hamiltonian import ( # noqa: E501 F401 DeviceHamiltonianValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( # noqa: F401 +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( # noqa: E501 F401 DeviceLocalDetuningValidator, ) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index d57822d3..52e5d42f 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -1,13 +1,14 @@ +from decimal import Decimal +from typing import Tuple + +from pydantic.v1.class_validators import root_validator + from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement import ( - AtomArrangementValidator + AtomArrangementValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( - PhysicalField +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceCapabilitiesConstants, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants -from pydantic.v1.class_validators import root_validator -from decimal import Decimal -from typing import Tuple def _y_distance(site_1: Tuple[Decimal, Decimal], site_2: Tuple[Decimal, Decimal]) -> Decimal: @@ -18,15 +19,14 @@ def _y_distance(site_1: Tuple[Decimal, Decimal], site_2: Tuple[Decimal, Decimal] class DeviceAtomArrangementValidator(AtomArrangementValidator): capabilities: DeviceCapabilitiesConstants - + @root_validator(pre=True, skip_on_failure=True) def sites_not_empty(cls, values): sites = values["sites"] if not sites: raise ValueError("Sites can not be empty.") return values - - + # The maximum allowable precision in the coordinates is SITE_PRECISION @root_validator(pre=True, skip_on_failure=True) def sites_defined_with_right_precision(cls, values): @@ -37,10 +37,11 @@ def sites_defined_with_right_precision(cls, values): [Decimal(str(coordinate)) % capabilities.SITE_PRECISION == 0 for coordinate in s] ): raise ValueError( - f"Coordinates {idx}({s}) is defined with too high precision; they must be multiples of {capabilities.SITE_PRECISION} meters" + f"Coordinates {idx}({s}) is defined with too high precision;\ + they must be multiples of {capabilities.SITE_PRECISION} meters" ) return values - + # Number of sites must not exceeds MAX_SITES @root_validator(pre=True, skip_on_failure=True) def sites_not_too_many(cls, values): @@ -49,11 +50,13 @@ def sites_not_too_many(cls, values): num_sites = len(sites) if num_sites > capabilities.MAX_SITES: raise ValueError( - f"There are too many sites ({num_sites}); there must be at most {capabilities.MAX_SITES} sites" + f"There are too many sites ({num_sites}); there must be at most\ + {capabilities.MAX_SITES} sites" ) return values - - # The y coordinates of any two lattice sites must either be equal or differ by at least MIN_ROW_DISTANCE. + + # The y coordinates of any two lattice sites must either be equal + # or differ by at least MIN_ROW_DISTANCE. @root_validator(pre=True, skip_on_failure=True) def sites_in_rows(cls, values): sites = values["sites"] @@ -68,11 +71,11 @@ def sites_in_rows(cls, values): continue if row_distance < min_allowed_distance: raise ValueError( - f"Sites {s1} and site {s2} have y-separation ({row_distance}). It must either be exactly zero or not smaller than {min_allowed_distance} meters" + f"Sites {s1} and site {s2} have y-separation ({row_distance}). It must\ + either be exactly zero or not smaller than {min_allowed_distance} meters" ) return values - - + # The number of filled lattice sites must not exceed MAX_FILLED_SITES. @root_validator(pre=True, skip_on_failure=True) def atom_number_limit(cls, values): @@ -81,7 +84,7 @@ def atom_number_limit(cls, values): qubits = sum(filling) if qubits > capabilities.MAX_FILLED_SITES: raise ValueError( - f"Filling has {qubits} '1' entries; is must have not more than {capabilities.MAX_FILLED_SITES}" + f"Filling has {qubits} '1' entries; is must have not\ + more than {capabilities.MAX_FILLED_SITES}" ) return values - diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py index cc16f9f4..eb342b2b 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py @@ -1,16 +1,17 @@ -from braket.analog_hamiltonian_simulator.rydberg.validators.capabilities_constants import ( - CapabilitiesConstants -) from decimal import Decimal from typing import Optional +from braket.analog_hamiltonian_simulator.rydberg.validators.capabilities_constants import ( + CapabilitiesConstants, +) + class DeviceCapabilitiesConstants(CapabilitiesConstants): MAX_SITES: int SITE_PRECISION: Decimal MAX_FILLED_SITES: int MIN_ROW_DISTANCE: Decimal - + GLOBAL_TIME_PRECISION: Decimal GLOBAL_AMPLITUDE_VALUE_PRECISION: Decimal GLOBAL_AMPLITUDE_SLOPE_MAX: Decimal @@ -20,7 +21,7 @@ class DeviceCapabilitiesConstants(CapabilitiesConstants): GLOBAL_PHASE_VALUE_MIN: Decimal GLOBAL_PHASE_VALUE_MAX: Decimal GLOBAL_PHASE_VALUE_PRECISION: Decimal - + LOCAL_RYDBERG_CAPABILITIES: bool = False LOCAL_MAGNITUDE_SLOPE_MAX: Optional[Decimal] LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES: Optional[Decimal] @@ -33,4 +34,3 @@ class DeviceCapabilitiesConstants(CapabilitiesConstants): MAGNITUDE_PATTERN_VALUE_MIN: Optional[Decimal] MAGNITUDE_PATTERN_VALUE_MAX: Optional[Decimal] MAX_NET_DETUNING: Optional[Decimal] - \ No newline at end of file diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py index db5e01ac..906e3ace 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py @@ -1,22 +1,24 @@ -from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import ( - DrivingFieldValidator -) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import DeviceCapabilitiesConstants from pydantic.v1.class_validators import root_validator -from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( - PhysicalField + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceCapabilitiesConstants, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import ( + DrivingFieldValidator, ) from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( - validate_time_precision, - validate_time_separation, - validate_value_precision, - validate_max_absolute_slope, - validate_value_range_with_warning + validate_max_absolute_slope, + validate_time_precision, + validate_time_separation, + validate_value_precision, + validate_value_range_with_warning, ) +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import PhysicalField + class DeviceDrivingFieldValidator(DrivingFieldValidator): capabilities: DeviceCapabilitiesConstants - + # Amplitude must start and end at 0.0 @root_validator(pre=True, skip_on_failure=True) def amplitude_start_and_end_values(cls, values): @@ -27,11 +29,11 @@ def amplitude_start_and_end_values(cls, values): start_value, end_value = time_series_values[0], time_series_values[-1] if start_value != 0 or end_value != 0: raise ValueError( - f"The values of the Rabi frequency at the first and last time points are {start_value}, {end_value}; they both must be both 0." + f"The values of the Rabi frequency at the first and last time points are \ + {start_value}, {end_value}; they both must be both 0." ) return values - - + @root_validator(pre=True, skip_on_failure=True) def amplitude_time_precision_is_correct(cls, values): amplitude = values["amplitude"] @@ -41,7 +43,7 @@ def amplitude_time_precision_is_correct(cls, values): amplitude_obj.time_series.times, capabilities.GLOBAL_TIME_PRECISION, "amplitude" ) return values - + @root_validator(pre=True, skip_on_failure=True) def amplitude_timepoint_not_too_close(cls, values): amplitude = values["amplitude"] @@ -50,8 +52,7 @@ def amplitude_timepoint_not_too_close(cls, values): amplitude["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "amplitude" ) return values - - + @root_validator(pre=True, skip_on_failure=True) def amplitude_value_precision_is_correct(cls, values): amplitude = values["amplitude"] @@ -63,8 +64,7 @@ def amplitude_value_precision_is_correct(cls, values): "amplitude", ) return values - - + @root_validator(pre=True, skip_on_failure=True) def amplitude_slopes_not_too_steep(cls, values): amplitude = values["amplitude"] @@ -79,7 +79,6 @@ def amplitude_slopes_not_too_steep(cls, values): "amplitude", ) return values - @root_validator(pre=True, skip_on_failure=True) def phase_time_precision_is_correct(cls, values): @@ -90,7 +89,7 @@ def phase_time_precision_is_correct(cls, values): phase_obj.time_series.times, capabilities.GLOBAL_TIME_PRECISION, "phase" ) return values - + @root_validator(pre=True, skip_on_failure=True) def phase_timepoint_not_too_close(cls, values): phase = values["phase"] @@ -99,7 +98,7 @@ def phase_timepoint_not_too_close(cls, values): phase["time_series"]["times"], capabilities.GLOBAL_MIN_TIME_SEPARATION, "phase" ) return values - + @root_validator(pre=True, skip_on_failure=True) def phase_values_start_with_0(cls, values): phase = values["phase"] @@ -110,7 +109,7 @@ def phase_values_start_with_0(cls, values): f"The first value of of driving field phase is {phase_values[0]}; it must be 0." ) return values - + @root_validator(pre=True, skip_on_failure=True) def phase_values_within_range(cls, values): phase = values["phase"] @@ -122,8 +121,7 @@ def phase_values_within_range(cls, values): "phase", ) return values - - + @root_validator(pre=True, skip_on_failure=True) def phase_value_precision_is_correct(cls, values): phase = values["phase"] @@ -133,7 +131,6 @@ def phase_value_precision_is_correct(cls, values): phase_obj.time_series.values, capabilities.GLOBAL_PHASE_VALUE_PRECISION, "phase" ) return values - @root_validator(pre=True, skip_on_failure=True) def detuning_time_precision_is_correct(cls, values): @@ -167,4 +164,4 @@ def detuning_slopes_not_too_steep(cls, values): capabilities.GLOBAL_DETUNING_SLOPE_MAX, "detuning", ) - return values \ No newline at end of file + return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py index b619a7b9..e733f623 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py @@ -1,12 +1,11 @@ from pydantic.v1.class_validators import root_validator -from braket.analog_hamiltonian_simulator.rydberg.validators.hamiltonian import \ - HamiltonianValidator -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_capabilities_constants import DeviceCapabilitiesConstants - + +from braket.analog_hamiltonian_simulator.rydberg.validators.hamiltonian import HamiltonianValidator + + class DeviceHamiltonianValidator(HamiltonianValidator): LOCAL_RYDBERG_CAPABILITIES: bool = False - + @root_validator(pre=True, skip_on_failure=True) def max_zero_local_detuning(cls, values): LOCAL_RYDBERG_CAPABILITIES = values["LOCAL_RYDBERG_CAPABILITIES"] @@ -14,8 +13,8 @@ def max_zero_local_detuning(cls, values): if not LOCAL_RYDBERG_CAPABILITIES: if len(local_detuning) > 0: raise ValueError( - f"Local detuning cannot be specified; \ + f"Local detuning cannot be specified; \ {len(local_detuning)} are given. Specifying local \ detuning is an experimental capability, use Braket Direct to request access." - ) + ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py index 2e0f4dcd..5cc6e7ec 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py @@ -13,18 +13,12 @@ from braket.ir.ahs.program_v1 import Program -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( DeviceAtomArrangementValidator, -) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( - DeviceCapabilitiesConstants -) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( - DeviceDrivingFieldValidator -) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_hamiltonian import DeviceHamiltonianValidator -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_local_detuning import ( - DeviceLocalDetuningValidator + DeviceCapabilitiesConstants, + DeviceDrivingFieldValidator, + DeviceHamiltonianValidator, + DeviceLocalDetuningValidator, ) from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( PhysicalFieldValidator, @@ -44,14 +38,19 @@ def validate_program(program: Program, device_capabilities: DeviceCapabilitiesCo """ ProgramValidator(capabilities=device_capabilities, **program.dict()) - DeviceAtomArrangementValidator(capabilities=device_capabilities, **program.setup.ahs_register.dict()) - DeviceHamiltonianValidator(LOCAL_RYDBERG_CAPABILITIES=device_capabilities.LOCAL_RYDBERG_CAPABILITIES, **program.hamiltonian.dict()) + DeviceAtomArrangementValidator( + capabilities=device_capabilities, **program.setup.ahs_register.dict() + ) + DeviceHamiltonianValidator( + LOCAL_RYDBERG_CAPABILITIES=device_capabilities.LOCAL_RYDBERG_CAPABILITIES, + **program.hamiltonian.dict() + ) for d_fields in program.hamiltonian.drivingFields: DeviceDrivingFieldValidator(capabilities=device_capabilities, **d_fields.dict()) amplitude = d_fields.amplitude phase = d_fields.phase detuning = d_fields.detuning - + PhysicalFieldValidator(**amplitude.dict()) TimeSeriesValidator(capabilities=device_capabilities, **amplitude.time_series.dict()) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py index 95566447..ab47b67a 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py @@ -1,22 +1,20 @@ -from braket.analog_hamiltonian_simulator.rydberg.validators.local_detuning import ( - LocalDetuningValidator -) -from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import ( - PhysicalField -) from pydantic.v1.class_validators import root_validator -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_capabilities_constants import DeviceCapabilitiesConstants +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceCapabilitiesConstants, +) from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( - validate_time_precision, validate_max_absolute_slope, - validate_time_separation + validate_time_precision, + validate_time_separation, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.local_detuning import ( + LocalDetuningValidator, ) +from braket.analog_hamiltonian_simulator.rydberg.validators.physical_field import PhysicalField -from pprint import pprint -class DeviceLocalDetuningValidator(LocalDetuningValidator): +class DeviceLocalDetuningValidator(LocalDetuningValidator): capabilities: DeviceCapabilitiesConstants @root_validator(pre=True, skip_on_failure=True) @@ -24,13 +22,13 @@ def check_local_rydberg_capabilities(cls, values): capabilities = values["capabilities"] if not capabilities.LOCAL_RYDBERG_CAPABILITIES: raise ValueError( - "Local Rydberg capabilities information has not been \ + "Local Rydberg capabilities information has not been \ provided for local detuning." - ) + ) return values - - - # Rule: The number of locally-addressed sites must not exceed rydberg.local.number_local_detuning_sites + + # Rule: The number of locally-addressed sites must not exceed + # rydberg.local.number_local_detuning_sites @root_validator(pre=True, skip_on_failure=True) def magnitude_pattern_have_not_too_many_nonzeros(cls, values): magnitude = values["magnitude"] @@ -39,11 +37,13 @@ def magnitude_pattern_have_not_too_many_nonzeros(cls, values): num_nonzeros = sum([p != 0.0 for p in pattern]) if num_nonzeros > capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES: raise ValueError( - f"Number of nonzero magnitude pattern values is {num_nonzeros}; it must not be more than {capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES}" + f"Number of nonzero magnitude pattern values is {num_nonzeros};\ + it must not be more than {capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES}" ) return values - - # Rule: The Rydberg local detuning times have a resolution of at least rydberg.local.time_resolution + + # Rule: The Rydberg local detuning times have a + # resolution of at least rydberg.local.time_resolution @root_validator(pre=True, skip_on_failure=True) def magnitude_time_precision_is_correct(cls, values): magnitude = values["magnitude"] @@ -53,7 +53,7 @@ def magnitude_time_precision_is_correct(cls, values): magnitude_obj.time_series.times, capabilities.LOCAL_TIME_PRECISION, "magnitude" ) return values - + # Rule: The Rydberg local detuning times must be spaced at least rydberg.local.time_delta_min @root_validator(pre=True, skip_on_failure=True) def magnitude_timepoint_not_too_close(cls, values): @@ -62,9 +62,9 @@ def magnitude_timepoint_not_too_close(cls, values): times = magnitude["time_series"]["times"] validate_time_separation(times, capabilities.LOCAL_MIN_TIME_SEPARATION, "magnitude") return values - - - # Rule: The Rydberg local detuning slew rate must not exceed rydberg.local.detuning_slew_rate_max + + # Rule: The Rydberg local detuning slew rate must + # not exceed rydberg.local.detuning_slew_rate_max @root_validator(pre=True, skip_on_failure=True) def magnitude_slopes_not_too_steep(cls, values): magnitude = values["magnitude"] @@ -90,6 +90,8 @@ def local_detuning_start_and_end_values(cls, values): start_value, end_value = time_series_values[0], time_series_values[-1] if start_value != 0 or end_value != 0: raise ValueError( - f"The values of the shifting field magnitude time series at the first and last time points are {start_value}, {end_value}; they both must be both 0." + f"The values of the shifting field magnitude time series at the first\ + and last time points are {start_value}, {end_value};\ + they both must be both 0." ) - return values \ No newline at end of file + return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py index f2057dcc..699828c7 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py @@ -104,14 +104,17 @@ def validate_net_detuning_with_warning( # Return immediately if there is an atom has net detuning # exceeding MAX_NET_DETUNING at a time point return program - + + # Two time points cannot be too close, assuming the time points are sorted ascendingly def validate_time_separation(times: List[Decimal], min_time_separation: Decimal, name: str): for i in range(len(times) - 1): time_diff = times[i + 1] - times[i] if time_diff < min_time_separation: raise ValueError( - f"Time points of {name} time_series, {i} ({times[i]}) and {i+1} ({times[i+1]}), are too close; they are separated by {time_diff} seconds. It must be at least {min_time_separation} seconds" + f"Time points of {name} time_series, {i} ({times[i]}) and\ + {i + 1} ({times[i + 1]}), are too close; they are separated\ + by {time_diff} seconds. It must be at least {min_time_separation} seconds" ) @@ -120,23 +123,31 @@ def validate_value_precision(values: List[Decimal], max_precision: Decimal, name for idx, v in enumerate(values): if v % max_precision != 0: raise ValueError( - f"Value {idx} ({v}) in {name} time_series is defined with too many digits; it must be an integer multiple of {max_precision}" + f"Value {idx} ({v}) in {name} time_series is defined with too many digits;\ + it must be an integer multiple of {max_precision}" ) - + + def validate_max_absolute_slope( times: List[Decimal], values: List[Decimal], max_slope: Decimal, name: str ): - # Raise ValueError if at any time the time series (times, values) rises/falls faster than allowed + # Raise ValueError if at any time the time series (times, values) + # rises/falls faster than allowed for idx in range(len(values) - 1): slope = (values[idx + 1] - values[idx]) / (times[idx + 1] - times[idx]) if abs(slope) > max_slope: raise ValueError( - f"For the {name} field, rate of change of values (between the {idx}-th and the {idx+1}-th times) is {abs(slope)}, more than {max_slope}" + f"For the {name} field, rate of change of values\ + (between the {idx}-th and the {idx + 1}-th times)\ + is {abs(slope)}, more than {max_slope}" ) - + + def validate_time_precision(times: List[Decimal], time_precision: Decimal, name: str): for idx, t in enumerate(times): if t % time_precision != 0: raise ValueError( - f"time point {idx} ({t}) of {name} time_series is defined with too many digits; it must be an integer multiple of {time_precision}" - ) \ No newline at end of file + f"time point {idx} ({t}) of {name} time_series is\ + defined with too many digits; it must be an\ + integer multiple of {time_precision}" + ) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py index 7d51c6a1..515d958a 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py @@ -1,43 +1,47 @@ -import pytest from decimal import Decimal -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_capabilities_constants import DeviceCapabilitiesConstants - + +import pytest + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceCapabilitiesConstants, +) + + @pytest.fixture def non_local_capabilities_constants(): capabilities_dict = { - 'BOUNDING_BOX_SIZE_X': Decimal('0.000075'), - 'BOUNDING_BOX_SIZE_Y': Decimal('0.000076'), - 'DIMENSIONS': 2, - 'GLOBAL_AMPLITUDE_SLOPE_MAX': Decimal('250000000000000'), - 'GLOBAL_AMPLITUDE_VALUE_MAX': Decimal('15800000.0'), - 'GLOBAL_AMPLITUDE_VALUE_MIN': Decimal('0.0'), - 'GLOBAL_AMPLITUDE_VALUE_PRECISION': Decimal('400.0'), - 'GLOBAL_DETUNING_SLOPE_MAX': Decimal('250000000000000'), - 'GLOBAL_DETUNING_VALUE_MAX': Decimal('125000000.0'), - 'GLOBAL_DETUNING_VALUE_MIN': Decimal('-125000000.0'), - 'GLOBAL_DETUNING_VALUE_PRECISION': Decimal('0.2'), - 'GLOBAL_MIN_TIME_SEPARATION': Decimal('1E-8'), - 'GLOBAL_PHASE_VALUE_MAX': Decimal('99.0'), - 'GLOBAL_PHASE_VALUE_MIN': Decimal('-99.0'), - 'GLOBAL_PHASE_VALUE_PRECISION': Decimal('5E-7'), - 'GLOBAL_TIME_PRECISION': Decimal('1E-9'), - 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX': None, - 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN': None, - 'LOCAL_MAGNITUDE_SLOPE_MAX': None, - 'LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES': None, - 'LOCAL_MIN_TIME_SEPARATION': None, - 'LOCAL_RYDBERG_CAPABILITIES': False, - 'LOCAL_TIME_PRECISION': None, - 'MAGNITUDE_PATTERN_VALUE_MAX': None, - 'MAGNITUDE_PATTERN_VALUE_MIN': None, - 'MAX_FILLED_SITES': 4, - 'MAX_NET_DETUNING': None, - 'MAX_SITES': 8, - 'MAX_TIME': Decimal('0.000004'), - 'MIN_DISTANCE': Decimal('0.000004'), - 'MIN_ROW_DISTANCE': Decimal('0.000004'), - 'SITE_PRECISION': Decimal('1E-7') + "BOUNDING_BOX_SIZE_X": Decimal("0.000075"), + "BOUNDING_BOX_SIZE_Y": Decimal("0.000076"), + "DIMENSIONS": 2, + "GLOBAL_AMPLITUDE_SLOPE_MAX": Decimal("250000000000000"), + "GLOBAL_AMPLITUDE_VALUE_MAX": Decimal("15800000.0"), + "GLOBAL_AMPLITUDE_VALUE_MIN": Decimal("0.0"), + "GLOBAL_AMPLITUDE_VALUE_PRECISION": Decimal("400.0"), + "GLOBAL_DETUNING_SLOPE_MAX": Decimal("250000000000000"), + "GLOBAL_DETUNING_VALUE_MAX": Decimal("125000000.0"), + "GLOBAL_DETUNING_VALUE_MIN": Decimal("-125000000.0"), + "GLOBAL_DETUNING_VALUE_PRECISION": Decimal("0.2"), + "GLOBAL_MIN_TIME_SEPARATION": Decimal("1E-8"), + "GLOBAL_PHASE_VALUE_MAX": Decimal("99.0"), + "GLOBAL_PHASE_VALUE_MIN": Decimal("-99.0"), + "GLOBAL_PHASE_VALUE_PRECISION": Decimal("5E-7"), + "GLOBAL_TIME_PRECISION": Decimal("1E-9"), + "LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX": None, + "LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN": None, + "LOCAL_MAGNITUDE_SLOPE_MAX": None, + "LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES": None, + "LOCAL_MIN_TIME_SEPARATION": None, + "LOCAL_RYDBERG_CAPABILITIES": False, + "LOCAL_TIME_PRECISION": None, + "MAGNITUDE_PATTERN_VALUE_MAX": None, + "MAGNITUDE_PATTERN_VALUE_MIN": None, + "MAX_FILLED_SITES": 4, + "MAX_NET_DETUNING": None, + "MAX_SITES": 8, + "MAX_TIME": Decimal("0.000004"), + "MIN_DISTANCE": Decimal("0.000004"), + "MIN_ROW_DISTANCE": Decimal("0.000004"), + "SITE_PRECISION": Decimal("1E-7"), } return DeviceCapabilitiesConstants(**capabilities_dict) @@ -45,17 +49,17 @@ def non_local_capabilities_constants(): @pytest.fixture def capabilities_with_local_rydberg(non_local_capabilities_constants): local_rydberg_constants = { - 'LOCAL_RYDBERG_CAPABILITIES': True, - 'LOCAL_TIME_PRECISION': Decimal('1e-9'), - 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX': Decimal('125000000.0'), - 'LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN': Decimal('0.0'), - 'LOCAL_MAGNITUDE_SLOPE_MAX': Decimal('1256600000000000.0'), - 'LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES': Decimal('5e-06'), - 'LOCAL_MIN_TIME_SEPARATION': Decimal('1E-8'), - 'LOCAL_MAX_NONZERO_PATTERN_VALUES': 200, - 'MAGNITUDE_PATTERN_VALUE_MAX': Decimal('1.0'), - 'MAGNITUDE_PATTERN_VALUE_MIN': Decimal('0.0'), + "LOCAL_RYDBERG_CAPABILITIES": True, + "LOCAL_TIME_PRECISION": Decimal("1e-9"), + "LOCAL_MAGNITUDE_SEQUENCE_VALUE_MAX": Decimal("125000000.0"), + "LOCAL_MAGNITUDE_SEQUENCE_VALUE_MIN": Decimal("0.0"), + "LOCAL_MAGNITUDE_SLOPE_MAX": Decimal("1256600000000000.0"), + "LOCAL_MIN_DISTANCE_BETWEEN_SHIFTED_SITES": Decimal("5e-06"), + "LOCAL_MIN_TIME_SEPARATION": Decimal("1E-8"), + "LOCAL_MAX_NONZERO_PATTERN_VALUES": 200, + "MAGNITUDE_PATTERN_VALUE_MAX": Decimal("1.0"), + "MAGNITUDE_PATTERN_VALUE_MIN": Decimal("0.0"), } capabilities_dict = non_local_capabilities_constants.dict() capabilities_dict.update(local_rydberg_constants) - return DeviceCapabilitiesConstants(**capabilities_dict) \ No newline at end of file + return DeviceCapabilitiesConstants(**capabilities_dict) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py index 4fdfcf0b..9204e8fc 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py @@ -1,25 +1,22 @@ -import pytest -from braket.analog_hamiltonian_simulator.rydberg.constants import capabilities_constants -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_capabilities_constants import DeviceCapabilitiesConstants from decimal import Decimal -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_atom_arrangement import DeviceAtomArrangementValidator - -from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement \ - import AtomArrangement - +import pytest from pydantic.v1.error_wrappers import ValidationError +from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement import AtomArrangement +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceAtomArrangementValidator, +) + + @pytest.fixture def atom_arrangement_data(): return { "sites": [[0, 0], [0, 5e-6], [5e-6, 0], [5e-6, 10e-6]], "filling": [1, 0, 1, 0], } - - + + @pytest.fixture def mock_atom_arrangement_data(): data = { @@ -55,12 +52,13 @@ def mock_atom_arrangement_data(): ], ) def test_atom_arrangement_sites_or_fillings_empty( - sites, filling, error_message, mock_atom_arrangement_data, - capabilities_with_local_rydberg -): + sites, filling, error_message, mock_atom_arrangement_data, capabilities_with_local_rydberg +): mock_atom_arrangement_data["sites"] = sites mock_atom_arrangement_data["filling"] = filling - _assert_atom_arrangement(mock_atom_arrangement_data, error_message, capabilities_with_local_rydberg) + _assert_atom_arrangement( + mock_atom_arrangement_data, error_message, capabilities_with_local_rydberg + ) def test_valid_atom_array(atom_arrangement_data, capabilities_with_local_rydberg): @@ -78,12 +76,14 @@ def test_valid_atom_array(atom_arrangement_data, capabilities_with_local_rydberg ( [[1.1e-6, 1.1e-6], [2.2e-6, 7.31e-6]], [1, 0], - "Coordinates 1([2.2e-06, 7.31e-06]) is defined with too high precision; they must be multiples of 1E-7 meters", + "Coordinates 1([2.2e-06, 7.31e-06]) is defined with too high precision;\ + they must be multiples of 1E-7 meters", ), ( [[3.201e-6, 0.0], [0.00, 4.1e-6], [-1.101e-6, 8.11e-6]], [1, 0, 1], - "Coordinates 0([3.201e-06, 0.0]) is defined with too high precision; they must be multiples of 1E-7 meters", + "Coordinates 0([3.201e-06, 0.0]) is defined with too high precision;\ + they must be multiples of 1E-7 meters", ), ], ) @@ -98,19 +98,12 @@ def test_atom_arrangement_sites_defined_with_right_precision( ) - - -def _assert_atom_arrangement( - data, error_message, device_capabilities_constants -): +def _assert_atom_arrangement(data, error_message, device_capabilities_constants): with pytest.raises(ValidationError) as e: - DeviceAtomArrangementValidator( - capabilities=device_capabilities_constants, **data - ) + DeviceAtomArrangementValidator(capabilities=device_capabilities_constants, **data) assert error_message in str(e.value) - - - + + def test_atom_arrangement_sites_not_too_many( mock_atom_arrangement_data, non_local_capabilities_constants ): @@ -122,24 +115,29 @@ def test_atom_arrangement_sites_not_too_many( _assert_atom_arrangement( mock_atom_arrangement_data, error_message, non_local_capabilities_constants ) - - + + @pytest.mark.parametrize( "sites, filling,error_message", [ ( [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("2.4e-6")]], [0, 1], - "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), Decimal('0.0000024')] have y-separation (0.0000024). It must either be exactly zero or not smaller than 0.000004 meters", + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'),\ + Decimal('0.0000024')] have y-separation (0.0000024). It must either be\ + exactly zero or not smaller than 0.000004 meters", ), ( [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("1.4e-6")]], [0, 1], - "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), Decimal('0.0000014')] have y-separation (0.0000014). It must either be exactly zero or not smaller than 0.000004 meters", + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'),\ + Decimal('0.0000014')] have y-separation (0.0000014). It must either\ + be exactly zero or not smaller than 0.000004 meters", ), ], ) -# Rule: All sites in the lattice must be separated vertically by at least lattice.geometry.spacing_vertical_min +# Rule: All sites in the lattice must be separated vertically +# by at least lattice.geometry.spacing_vertical_min def test_atom_arrangement_sites_in_rows( sites, filling, @@ -154,16 +152,21 @@ def test_atom_arrangement_sites_in_rows( error_message, non_local_capabilities_constants, ) - - + + def test_atom_arrangement_filling_atom_number_limit( mock_atom_arrangement_data, non_local_capabilities_constants ): filling = [1] * (non_local_capabilities_constants.MAX_FILLED_SITES + 1) mock_atom_arrangement_data["filling"] = filling - mock_atom_arrangement_data["sites"] = [[0, 0], [0, 0.00004], [0, 0.00005], [0.00005, 0.00004], [0.00005, 0]] + mock_atom_arrangement_data["sites"] = [ + [0, 0], + [0, 0.00004], + [0, 0.00005], + [0.00005, 0.00004], + [0.00005, 0], + ] error_message = "Filling has 5 '1' entries; is must have not more than 4" _assert_atom_arrangement( mock_atom_arrangement_data, error_message, non_local_capabilities_constants ) - \ No newline at end of file diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py index fc5a67e9..e1adcec2 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py @@ -1,9 +1,10 @@ import pytest from pydantic.v1.error_wrappers import ValidationError -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_driving_field import DeviceDrivingFieldValidator -from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field \ - import DrivingField + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceDrivingFieldValidator, +) +from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import DrivingField @pytest.fixture @@ -31,7 +32,8 @@ def driving_field_data(): }, }, } - + + @pytest.fixture def mock_driving_field_data(): data = { @@ -62,7 +64,9 @@ def mock_driving_field_data(): def test_device_driving_field(driving_field_data, non_local_capabilities_constants): try: - DeviceDrivingFieldValidator(capabilities=non_local_capabilities_constants, **driving_field_data) + DeviceDrivingFieldValidator( + capabilities=non_local_capabilities_constants, **driving_field_data + ) except ValidationError as e: pytest.fail(f"Validate test is failing : {str(e)}") @@ -73,133 +77,158 @@ def test_device_driving_field(driving_field_data, non_local_capabilities_constan ( [0.0, 12.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "amplitude", - "time point 1 (2.21E-8) of amplitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of amplitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "phase", - "time point 1 (2.21E-8) of phase time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of phase time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "detuning", - "time point 1 (2.21E-8) of detuning time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of detuning time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ], ) -# Rule: The times for any component of the effective Hamiltonian have a maximum precision of rydberg.global.time_resolution +# Rule: The times for any component of the effective Hamiltonian +# have a maximum precision of rydberg.global.time_resolution def test_driving_field_time_precision_is_correct( times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants ): mock_driving_field_data[field_name]["time_series"]["times"] = times _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) + def test_driving_field_no_detuning(mock_driving_field_data, non_local_capabilities_constants): mock_driving_field_data["detuning"]["time_series"]["times"].clear() mock_driving_field_data["detuning"]["time_series"]["values"].clear() try: - DeviceDrivingFieldValidator(capabilities=non_local_capabilities_constants, **mock_driving_field_data) + DeviceDrivingFieldValidator( + capabilities=non_local_capabilities_constants, **mock_driving_field_data + ) except ValidationError as e: pytest.fail(f"Validate test is failing : {str(e)}") - - + + @pytest.mark.parametrize( - "values, field_name, error_message", + "values, field_name, error_message", [ ( - [0.0, 22.1e-9, 12,1e-9, 0.0], - "amplitude", - "Value 1 (2.21E-8) in amplitude time_series is defined with too many digits; it must be an integer multiple of 400.0", + [0.0, 22.1e-9, 12, 1e-9, 0.0], + "amplitude", + "Value 1 (2.21E-8) in amplitude time_series is\ + defined with too many digits; it must be an integer multiple of 400.0", ) - ] -) + ], +) def test_driving_field_value_precision_is_correct( values, field_name, error_message, driving_field_data, non_local_capabilities_constants ): driving_field_data[field_name]["time_series"]["values"] = values _assert_driving_field(driving_field_data, error_message, non_local_capabilities_constants) + @pytest.mark.parametrize( "times, field_name, error_message", [ ( [0.0, 9e-9, 25e-9], "amplitude", - "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9], "phase", - "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9], "detuning", - "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "amplitude", - "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "phase", - "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "detuning", - "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close;\ + they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ], ) -# Rule: The times for any component of the effective Hamiltonian must be spaced by at least rydberg.global.time_delta_min +# Rule: The times for any component of the effective Hamiltonian +# must be spaced by at least rydberg.global.time_delta_min def test_driving_field_timepoint_not_too_close( times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants ): @@ -213,17 +242,20 @@ def test_driving_field_timepoint_not_too_close( ( [2.5e7, 2.5e7, 2.5e7, 0.0], "amplitude", - "The values of the Rabi frequency at the first and last time points are 25000000.0, 0.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points\ + are 25000000.0, 0.0; they both must be both 0.", ), ( [0.0, 2.5e7, 2.5e7, 2.5e7], "amplitude", - "The values of the Rabi frequency at the first and last time points are 0.0, 25000000.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points\ + are 0.0, 25000000.0; they both must be both 0.", ), ( [2.5e7, 2.5e7, 2.5e7, 2.5e7], "amplitude", - "The values of the Rabi frequency at the first and last time points are 25000000.0, 25000000.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points\ + are 25000000.0, 25000000.0; they both must be both 0.", ), ], ) @@ -233,7 +265,7 @@ def test_driving_field_amplitude_start_and_end_values( ): mock_driving_field_data[field_name]["time_series"]["values"] = values _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) - + @pytest.mark.parametrize( "values, times, field_name, error_message", @@ -242,35 +274,48 @@ def test_driving_field_amplitude_start_and_end_values( [0.0, 2.5e7, 0.0], [0.0, 0.01e-6, 2.0e-6], "amplitude", - "For the amplitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", + "For the amplitude field, rate of change of values\ + (between the 0-th and the 1-th times)\ + is 2500000000000000.0, more than 250000000000000", ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], "amplitude", - "For the amplitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", - ), + "For the amplitude field, rate of change of values\ + (between the 0-th and the 1-th times)\ + is 2500000000000000.0, more than 250000000000000", + ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], "detuning", - "For the detuning field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 250000000000000", + "For the detuning field, rate of change of values\ + (between the 0-th and the 1-th times)\ + is 2500000000000000.0, more than 250000000000000", ), - ] + ], ) def test_driving_field_slopes_not_too_steep( - values, times, field_name, error_message, mock_driving_field_data, non_local_capabilities_constants + values, + times, + field_name, + error_message, + mock_driving_field_data, + non_local_capabilities_constants, ): mock_driving_field_data[field_name]["time_series"]["values"] = values mock_driving_field_data[field_name]["time_series"]["times"] = times _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) - + + def test_phase_values_start_with_0(mock_driving_field_data, non_local_capabilities_constants): mock_driving_field_data["phase"]["time_series"]["values"] = [0.1, 2.5e7] error_message = "The first value of of driving field phase is 0.1; it must be 0." _assert_driving_field(mock_driving_field_data, error_message, non_local_capabilities_constants) - + + def _assert_driving_field(data, error_message, device_capabilities_constants): with pytest.raises(ValidationError) as e: DeviceDrivingFieldValidator(capabilities=device_capabilities_constants, **data) - assert error_message in str(e.value) \ No newline at end of file + assert error_message in str(e.value) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py index 5b756609..9f73f417 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_hamiltonian.py @@ -1,9 +1,11 @@ import pytest from pydantic.v1.error_wrappers import ValidationError -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators \ - .device_hamiltonian import DeviceHamiltonianValidator - - + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceHamiltonianValidator, +) + + @pytest.fixture def hamiltonian_data(): return { @@ -41,27 +43,26 @@ def hamiltonian_data(): } ], } - + + def test_hamiltonian(hamiltonian_data): try: DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=True) except ValidationError as e: pytest.fail(f"Validate test is failing : {str(e)}") -@pytest.mark.parametrize( - "local_rydberg_exists", - [ - (True), - (False) - ] -) + +@pytest.mark.parametrize("local_rydberg_exists", [(True), (False)]) def test_hamiltonian_no_detuning(local_rydberg_exists, hamiltonian_data): hamiltonian_data["localDetuning"].clear() try: - DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=local_rydberg_exists) + DeviceHamiltonianValidator( + **hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=local_rydberg_exists + ) except ValidationError as e: pytest.fail(f"Validate test is failing : {str(e)}") + def test_no_local_rydberg_capabilities(hamiltonian_data): error_message = "Local detuning cannot be specified; \ 1 are given. Specifying local \ @@ -69,4 +70,3 @@ def test_no_local_rydberg_capabilities(hamiltonian_data): with pytest.raises(ValidationError) as e: DeviceHamiltonianValidator(**hamiltonian_data, LOCAL_RYDBERG_CAPABILITIES=False) assert error_message in str(e.value) - diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py index 5a33c566..16ab59bc 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py @@ -1,10 +1,11 @@ import pytest -from pydantic.v1.error_wrappers import ValidationError from braket.ir.ahs.local_detuning import LocalDetuning -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.\ - device_local_detuning import DeviceLocalDetuningValidator - - +from pydantic.v1.error_wrappers import ValidationError + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( + DeviceLocalDetuningValidator, +) + @pytest.fixture def local_detuning_data(): @@ -30,30 +31,36 @@ def mock_local_detuning_data(): return LocalDetuning.parse_obj(data).dict() - def test_valid_detuning(local_detuning_data, capabilities_with_local_rydberg): try: - DeviceLocalDetuningValidator(capabilities=capabilities_with_local_rydberg, **local_detuning_data) + DeviceLocalDetuningValidator( + capabilities=capabilities_with_local_rydberg, **local_detuning_data + ) except ValidationError as e: pytest.fail(f"Validate test is failing: {str(e.value)}") - + + def test_validation_no_time_series(mock_local_detuning_data, capabilities_with_local_rydberg): mock_local_detuning_data["magnitude"]["time_series"]["times"].clear() mock_local_detuning_data["magnitude"]["time_series"]["values"].clear() try: - DeviceLocalDetuningValidator(capabilities=capabilities_with_local_rydberg, **mock_local_detuning_data) + DeviceLocalDetuningValidator( + capabilities=capabilities_with_local_rydberg, **mock_local_detuning_data + ) except ValidationError as e: pytest.fail(f"Validate test is failing: {str(e.value)}") - + + def test_validation_no_detuning_data(mock_local_detuning_data, non_local_capabilities_constants): error_message = "Local Rydberg capabilities information has not been \ provided for local detuning." non_local_capabilities_constants.LOCAL_RYDBERG_CAPABILITIES = False with pytest.raises(ValueError) as e: - DeviceLocalDetuningValidator(capabilities=non_local_capabilities_constants, **mock_local_detuning_data) + DeviceLocalDetuningValidator( + capabilities=non_local_capabilities_constants, **mock_local_detuning_data + ) assert error_message in str(e.value) - def test_shifting_field_magnitude_pattern_have_not_too_many_nonzeros( @@ -73,12 +80,16 @@ def test_shifting_field_magnitude_pattern_have_not_too_many_nonzeros( ( [0.0, 2.5e7, 0.0], [0.0, 0.01e-6, 2.0e-6], - "For the magnitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 1256600000000000.0", + "For the magnitude field, rate of change of values\ + (between the 0-th and the 1-th times)\ + is 2500000000000000.0, more than 1256600000000000.0", ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], - "For the magnitude field, rate of change of values (between the 0-th and the 1-th times) is 2500000000000000.0, more than 1256600000000000.0", + "For the magnitude field, rate of change of values\ + (between the 0-th and the 1-th times)\ + is 2500000000000000.0, more than 1256600000000000.0", ), ], ) @@ -95,23 +106,28 @@ def test_local_detuning_slopes_not_too_steep( [ ( [0.0, 12.1e-9], - "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], - "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], - "time point 1 (1.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], - "time point 1 (2.21E-8) of magnitude time_series is defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of magnitude time_series is\ + defined with too many digits; it must be an integer multiple of 1E-9", ), ], ) -# Rule: The times for any component of the effective Hamiltonian have a maximum precision of rydberg.global.time_resolution +# Rule: The times for any component of the effective Hamiltonian have +# a maximum precision of rydberg.global.time_resolution def test_shifting_field_magnitude_time_precision_is_correct( times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg ): @@ -120,27 +136,33 @@ def test_shifting_field_magnitude_time_precision_is_correct( @pytest.mark.parametrize( - "times, error_message", + "times, error_message", [ ( - [0.0, 1.0, 2.0], - "The values of the shifting field magnitude time series at the first and last time points are 0.0, 2.0; they both must be both 0." - ), + [0.0, 1.0, 2.0], + "The values of the shifting field magnitude time series at\ + the first and last time points are 0.0, 2.0; they both must be both 0.", + ), ( - [0.2, 1.0, 0], - "The values of the shifting field magnitude time series at the first and last time points are 0.2, 0; they both must be both 0." - ), + [0.2, 1.0, 0], + "The values of the shifting field magnitude time series at\ + the first and last time points are 0.2, 0; they both must be both 0.", + ), ( - [0.0, 0.0, 1e-5], - "The values of the shifting field magnitude time series at the first and last time points are 0.0, 1e-05; they both must be both 0." - ), - ] + [0.0, 0.0, 1e-5], + "The values of the shifting field magnitude time series at\ + the first and last time points are 0.0, 1e-05; they both must be both 0.", + ), + ], ) -def test_shifting_start_and_end_are_zero(times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg): +def test_shifting_start_and_end_are_zero( + times, error_message, mock_local_detuning_data, capabilities_with_local_rydberg +): mock_local_detuning_data["magnitude"]["time_series"]["values"] = times _assert_local_detuning(mock_local_detuning_data, error_message, capabilities_with_local_rydberg) + def _assert_local_detuning(data, error_message, device_capabilities_constants): with pytest.raises(ValidationError) as e: DeviceLocalDetuningValidator(capabilities=device_capabilities_constants, **data) - assert error_message in str(e.value) \ No newline at end of file + assert error_message in str(e.value) From 746ab2cb377425a6a97aaba921c8bf8976cd04c7 Mon Sep 17 00:00:00 2001 From: Nagji Date: Sun, 21 Jul 2024 19:57:44 -0700 Subject: [PATCH 08/10] fix: Fix circular dependency and error message/test strings resulting from style enforcement changes --- .../device_capabilities_constants.py | 0 .../validators/device_validators/__init__.py | 3 - .../device_atom_arrangement.py | 18 +-- .../device_validators/device_driving_field.py | 6 +- .../device_validators/device_hamiltonian.py | 9 +- .../device_validators/device_ir_validator.py | 4 +- .../device_local_detuning.py | 16 +-- .../validators/field_validator_util.py | 22 ++-- .../validators/device_validators/conftest.py | 2 +- .../test_device_atom_arrangement.py | 22 ++-- .../test_device_driving_field.py | 106 +++++++++--------- .../test_device_local_detuning.py | 45 ++++---- 12 files changed, 126 insertions(+), 127 deletions(-) rename src/braket/analog_hamiltonian_simulator/rydberg/validators/{device_validators => }/device_capabilities_constants.py (100%) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_capabilities_constants.py similarity index 100% rename from src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_capabilities_constants.py rename to src/braket/analog_hamiltonian_simulator/rydberg/validators/device_capabilities_constants.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py index cb068b2c..894e5e68 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/__init__.py @@ -1,9 +1,6 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_atom_arrangement import ( # noqa: E501 F401 DeviceAtomArrangementValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_capabilities_constants import ( # noqa: E501 F401 - DeviceCapabilitiesConstants, -) from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators.device_driving_field import ( # noqa: E501 F401 DeviceDrivingFieldValidator, ) diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py index 52e5d42f..ca19d962 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_atom_arrangement.py @@ -6,7 +6,7 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement import ( AtomArrangementValidator, ) -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( DeviceCapabilitiesConstants, ) @@ -37,8 +37,8 @@ def sites_defined_with_right_precision(cls, values): [Decimal(str(coordinate)) % capabilities.SITE_PRECISION == 0 for coordinate in s] ): raise ValueError( - f"Coordinates {idx}({s}) is defined with too high precision;\ - they must be multiples of {capabilities.SITE_PRECISION} meters" + f"Coordinates {idx}({s}) is defined with too high precision;" + f"they must be multiples of {capabilities.SITE_PRECISION} meters" ) return values @@ -50,8 +50,8 @@ def sites_not_too_many(cls, values): num_sites = len(sites) if num_sites > capabilities.MAX_SITES: raise ValueError( - f"There are too many sites ({num_sites}); there must be at most\ - {capabilities.MAX_SITES} sites" + f"There are too many sites ({num_sites}); there must be at most " + f"{capabilities.MAX_SITES} sites" ) return values @@ -71,8 +71,8 @@ def sites_in_rows(cls, values): continue if row_distance < min_allowed_distance: raise ValueError( - f"Sites {s1} and site {s2} have y-separation ({row_distance}). It must\ - either be exactly zero or not smaller than {min_allowed_distance} meters" + f"Sites {s1} and site {s2} have y-separation ({row_distance}). It must " + f"either be exactly zero or not smaller than {min_allowed_distance} meters" ) return values @@ -84,7 +84,7 @@ def atom_number_limit(cls, values): qubits = sum(filling) if qubits > capabilities.MAX_FILLED_SITES: raise ValueError( - f"Filling has {qubits} '1' entries; is must have not\ - more than {capabilities.MAX_FILLED_SITES}" + f"Filling has {qubits} '1' entries; it must have not " + f"more than {capabilities.MAX_FILLED_SITES}" ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py index 906e3ace..5f6f5abd 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_driving_field.py @@ -1,6 +1,6 @@ from pydantic.v1.class_validators import root_validator -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( DeviceCapabilitiesConstants, ) from braket.analog_hamiltonian_simulator.rydberg.validators.driving_field import ( @@ -29,8 +29,8 @@ def amplitude_start_and_end_values(cls, values): start_value, end_value = time_series_values[0], time_series_values[-1] if start_value != 0 or end_value != 0: raise ValueError( - f"The values of the Rabi frequency at the first and last time points are \ - {start_value}, {end_value}; they both must be both 0." + f"The values of the Rabi frequency at the first and last time points are " + f"{start_value}, {end_value}; they both must be nonzero." ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py index e733f623..ac9ce467 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_hamiltonian.py @@ -10,11 +10,10 @@ class DeviceHamiltonianValidator(HamiltonianValidator): def max_zero_local_detuning(cls, values): LOCAL_RYDBERG_CAPABILITIES = values["LOCAL_RYDBERG_CAPABILITIES"] local_detuning = values.get("localDetuning", []) - if not LOCAL_RYDBERG_CAPABILITIES: - if len(local_detuning) > 0: - raise ValueError( - f"Local detuning cannot be specified; \ + if not LOCAL_RYDBERG_CAPABILITIES and len(local_detuning): + raise ValueError( + f"Local detuning cannot be specified; \ {len(local_detuning)} are given. Specifying local \ detuning is an experimental capability, use Braket Direct to request access." - ) + ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py index 5cc6e7ec..a080f6d2 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py @@ -13,9 +13,11 @@ from braket.ir.ahs.program_v1 import Program +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( + DeviceCapabilitiesConstants, +) from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( DeviceAtomArrangementValidator, - DeviceCapabilitiesConstants, DeviceDrivingFieldValidator, DeviceHamiltonianValidator, DeviceLocalDetuningValidator, diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py index ab47b67a..6dcb6630 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_local_detuning.py @@ -1,6 +1,6 @@ from pydantic.v1.class_validators import root_validator -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( DeviceCapabilitiesConstants, ) from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( @@ -22,8 +22,8 @@ def check_local_rydberg_capabilities(cls, values): capabilities = values["capabilities"] if not capabilities.LOCAL_RYDBERG_CAPABILITIES: raise ValueError( - "Local Rydberg capabilities information has not been \ - provided for local detuning." + "Local Rydberg capabilities information has not been " + "provided for local detuning." ) return values @@ -37,8 +37,8 @@ def magnitude_pattern_have_not_too_many_nonzeros(cls, values): num_nonzeros = sum([p != 0.0 for p in pattern]) if num_nonzeros > capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES: raise ValueError( - f"Number of nonzero magnitude pattern values is {num_nonzeros};\ - it must not be more than {capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES}" + f"Number of nonzero magnitude pattern values is {num_nonzeros}; " + f"it must not be more than {capabilities.LOCAL_MAX_NONZERO_PATTERN_VALUES}" ) return values @@ -90,8 +90,8 @@ def local_detuning_start_and_end_values(cls, values): start_value, end_value = time_series_values[0], time_series_values[-1] if start_value != 0 or end_value != 0: raise ValueError( - f"The values of the shifting field magnitude time series at the first\ - and last time points are {start_value}, {end_value};\ - they both must be both 0." + f"The values of the shifting field magnitude time series at the first " + f"and last time points are {start_value}, {end_value}; " + f"they both must be nonzero." ) return values diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py index 699828c7..aefb1ce5 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/field_validator_util.py @@ -112,9 +112,9 @@ def validate_time_separation(times: List[Decimal], min_time_separation: Decimal, time_diff = times[i + 1] - times[i] if time_diff < min_time_separation: raise ValueError( - f"Time points of {name} time_series, {i} ({times[i]}) and\ - {i + 1} ({times[i + 1]}), are too close; they are separated\ - by {time_diff} seconds. It must be at least {min_time_separation} seconds" + f"Time points of {name} time_series, {i} ({times[i]}) and " + f"{i + 1} ({times[i + 1]}), are too close; they are separated " + f"by {time_diff} seconds. It must be at least {min_time_separation} seconds" ) @@ -123,8 +123,8 @@ def validate_value_precision(values: List[Decimal], max_precision: Decimal, name for idx, v in enumerate(values): if v % max_precision != 0: raise ValueError( - f"Value {idx} ({v}) in {name} time_series is defined with too many digits;\ - it must be an integer multiple of {max_precision}" + f"Value {idx} ({v}) in {name} time_series is defined with too many digits; " + f"it must be an integer multiple of {max_precision}" ) @@ -137,9 +137,9 @@ def validate_max_absolute_slope( slope = (values[idx + 1] - values[idx]) / (times[idx + 1] - times[idx]) if abs(slope) > max_slope: raise ValueError( - f"For the {name} field, rate of change of values\ - (between the {idx}-th and the {idx + 1}-th times)\ - is {abs(slope)}, more than {max_slope}" + f"For the {name} field, rate of change of values " + f"(between the {idx}-th and the {idx + 1}-th times) " + f"is {abs(slope)}, more than {max_slope}" ) @@ -147,7 +147,7 @@ def validate_time_precision(times: List[Decimal], time_precision: Decimal, name: for idx, t in enumerate(times): if t % time_precision != 0: raise ValueError( - f"time point {idx} ({t}) of {name} time_series is\ - defined with too many digits; it must be an\ - integer multiple of {time_precision}" + f"time point {idx} ({t}) of {name} time_series is " + f"defined with too many digits; it must be an " + f"integer multiple of {time_precision}" ) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py index 515d958a..e311c56e 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/conftest.py @@ -2,7 +2,7 @@ import pytest -from braket.analog_hamiltonian_simulator.rydberg.validators.device_validators import ( +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( DeviceCapabilitiesConstants, ) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py index 9204e8fc..ee309630 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_atom_arrangement.py @@ -76,14 +76,14 @@ def test_valid_atom_array(atom_arrangement_data, capabilities_with_local_rydberg ( [[1.1e-6, 1.1e-6], [2.2e-6, 7.31e-6]], [1, 0], - "Coordinates 1([2.2e-06, 7.31e-06]) is defined with too high precision;\ - they must be multiples of 1E-7 meters", + "Coordinates 1([2.2e-06, 7.31e-06]) is defined with too high precision;" + "they must be multiples of 1E-7 meters", ), ( [[3.201e-6, 0.0], [0.00, 4.1e-6], [-1.101e-6, 8.11e-6]], [1, 0, 1], - "Coordinates 0([3.201e-06, 0.0]) is defined with too high precision;\ - they must be multiples of 1E-7 meters", + "Coordinates 0([3.201e-06, 0.0]) is defined with too high precision;" + "they must be multiples of 1E-7 meters", ), ], ) @@ -123,16 +123,16 @@ def test_atom_arrangement_sites_not_too_many( ( [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("2.4e-6")]], [0, 1], - "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'),\ - Decimal('0.0000024')] have y-separation (0.0000024). It must either be\ - exactly zero or not smaller than 0.000004 meters", + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), " + "Decimal('0.0000024')] have y-separation (0.0000024). It must either be " + "exactly zero or not smaller than 0.000004 meters", ), ( [[Decimal("0.0"), Decimal("0.0")], [Decimal("5e-6"), Decimal("1.4e-6")]], [0, 1], - "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'),\ - Decimal('0.0000014')] have y-separation (0.0000014). It must either\ - be exactly zero or not smaller than 0.000004 meters", + "Sites [Decimal('0.0'), Decimal('0.0')] and site [Decimal('0.000005'), " + "Decimal('0.0000014')] have y-separation (0.0000014). It must either " + "be exactly zero or not smaller than 0.000004 meters", ), ], ) @@ -166,7 +166,7 @@ def test_atom_arrangement_filling_atom_number_limit( [0.00005, 0.00004], [0.00005, 0], ] - error_message = "Filling has 5 '1' entries; is must have not more than 4" + error_message = "Filling has 5 '1' entries; it must have not more than 4" _assert_atom_arrangement( mock_atom_arrangement_data, error_message, non_local_capabilities_constants ) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py index e1adcec2..939afcbb 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_driving_field.py @@ -77,74 +77,74 @@ def test_device_driving_field(driving_field_data, non_local_capabilities_constan ( [0.0, 12.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "phase", - "time point 1 (1.21E-8) of phase time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], "detuning", - "time point 1 (1.21E-8) of detuning time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "amplitude", - "time point 1 (1.21E-8) of amplitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of amplitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "phase", - "time point 1 (1.21E-8) of phase time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of phase time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], "detuning", - "time point 1 (1.21E-8) of detuning time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of detuning time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "amplitude", - "time point 1 (2.21E-8) of amplitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of amplitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "phase", - "time point 1 (2.21E-8) of phase time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of phase time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], "detuning", - "time point 1 (2.21E-8) of detuning time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of detuning time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ], ) @@ -174,8 +174,8 @@ def test_driving_field_no_detuning(mock_driving_field_data, non_local_capabiliti ( [0.0, 22.1e-9, 12, 1e-9, 0.0], "amplitude", - "Value 1 (2.21E-8) in amplitude time_series is\ - defined with too many digits; it must be an integer multiple of 400.0", + "Value 1 (2.21E-8) in amplitude time_series is " + "defined with too many digits; it must be an integer multiple of 400.0", ) ], ) @@ -192,38 +192,38 @@ def test_driving_field_value_precision_is_correct( ( [0.0, 9e-9, 25e-9], "amplitude", - "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9], "phase", - "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9], "detuning", - "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "amplitude", - "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of amplitude time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "phase", - "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of phase time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ( [0.0, 9e-9, 25e-9, 30e-9], "detuning", - "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close;\ - they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", + "Time points of detuning time_series, 0 (0.0) and 1 (9e-09), are too close; " + "they are separated by 9e-09 seconds. It must be at least 1E-8 seconds", ), ], ) @@ -242,20 +242,20 @@ def test_driving_field_timepoint_not_too_close( ( [2.5e7, 2.5e7, 2.5e7, 0.0], "amplitude", - "The values of the Rabi frequency at the first and last time points\ - are 25000000.0, 0.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points " + "are 25000000.0, 0.0; they both must be nonzero.", ), ( [0.0, 2.5e7, 2.5e7, 2.5e7], "amplitude", - "The values of the Rabi frequency at the first and last time points\ - are 0.0, 25000000.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points " + "are 0.0, 25000000.0; they both must be nonzero.", ), ( [2.5e7, 2.5e7, 2.5e7, 2.5e7], "amplitude", - "The values of the Rabi frequency at the first and last time points\ - are 25000000.0, 25000000.0; they both must be both 0.", + "The values of the Rabi frequency at the first and last time points " + "are 25000000.0, 25000000.0; they both must be nonzero.", ), ], ) @@ -274,25 +274,25 @@ def test_driving_field_amplitude_start_and_end_values( [0.0, 2.5e7, 0.0], [0.0, 0.01e-6, 2.0e-6], "amplitude", - "For the amplitude field, rate of change of values\ - (between the 0-th and the 1-th times)\ - is 2500000000000000.0, more than 250000000000000", + "For the amplitude field, rate of change of values " + "(between the 0-th and the 1-th times) " + "is 2500000000000000.0, more than 250000000000000", ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], "amplitude", - "For the amplitude field, rate of change of values\ - (between the 0-th and the 1-th times)\ - is 2500000000000000.0, more than 250000000000000", + "For the amplitude field, rate of change of values " + "(between the 0-th and the 1-th times) " + "is 2500000000000000.0, more than 250000000000000", ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], "detuning", - "For the detuning field, rate of change of values\ - (between the 0-th and the 1-th times)\ - is 2500000000000000.0, more than 250000000000000", + "For the detuning field, rate of change of values " + "(between the 0-th and the 1-th times) " + "is 2500000000000000.0, more than 250000000000000", ), ], ) diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py index 16ab59bc..6d2153e4 100644 --- a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_local_detuning.py @@ -53,8 +53,9 @@ def test_validation_no_time_series(mock_local_detuning_data, capabilities_with_l def test_validation_no_detuning_data(mock_local_detuning_data, non_local_capabilities_constants): - error_message = "Local Rydberg capabilities information has not been \ - provided for local detuning." + error_message = ( + "Local Rydberg capabilities information has not been " "provided for local detuning." + ) non_local_capabilities_constants.LOCAL_RYDBERG_CAPABILITIES = False with pytest.raises(ValueError) as e: DeviceLocalDetuningValidator( @@ -80,16 +81,16 @@ def test_shifting_field_magnitude_pattern_have_not_too_many_nonzeros( ( [0.0, 2.5e7, 0.0], [0.0, 0.01e-6, 2.0e-6], - "For the magnitude field, rate of change of values\ - (between the 0-th and the 1-th times)\ - is 2500000000000000.0, more than 1256600000000000.0", + "For the magnitude field, rate of change of values " + "(between the 0-th and the 1-th times) " + "is 2500000000000000.0, more than 1256600000000000.0", ), ( [0.0, 2.5e7, 2.5e7, 0.0], [0.0, 0.01e-6, 3.2e-6, 3.21e-6], - "For the magnitude field, rate of change of values\ - (between the 0-th and the 1-th times)\ - is 2500000000000000.0, more than 1256600000000000.0", + "For the magnitude field, rate of change of values " + "(between the 0-th and the 1-th times) " + "is 2500000000000000.0, more than 1256600000000000.0", ), ], ) @@ -106,23 +107,23 @@ def test_local_detuning_slopes_not_too_steep( [ ( [0.0, 12.1e-9], - "time point 1 (1.21E-8) of magnitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 4e-6], - "time point 1 (1.21E-8) of magnitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 12.1e-9, 22.1e-9], - "time point 1 (1.21E-8) of magnitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (1.21E-8) of magnitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ( [0.0, 22.1e-9, 12.1e-9], - "time point 1 (2.21E-8) of magnitude time_series is\ - defined with too many digits; it must be an integer multiple of 1E-9", + "time point 1 (2.21E-8) of magnitude time_series is " + "defined with too many digits; it must be an integer multiple of 1E-9", ), ], ) @@ -140,18 +141,18 @@ def test_shifting_field_magnitude_time_precision_is_correct( [ ( [0.0, 1.0, 2.0], - "The values of the shifting field magnitude time series at\ - the first and last time points are 0.0, 2.0; they both must be both 0.", + "The values of the shifting field magnitude time series at " + "the first and last time points are 0.0, 2.0; they both must be nonzero.", ), ( [0.2, 1.0, 0], - "The values of the shifting field magnitude time series at\ - the first and last time points are 0.2, 0; they both must be both 0.", + "The values of the shifting field magnitude time series at " + "the first and last time points are 0.2, 0; they both must be nonzero.", ), ( [0.0, 0.0, 1e-5], - "The values of the shifting field magnitude time series at\ - the first and last time points are 0.0, 1e-05; they both must be both 0.", + "The values of the shifting field magnitude time series at " + "the first and last time points are 0.0, 1e-05; they both must be nonzero.", ), ], ) From b6da5085636f6733fa2f2c0a83b44d3c87b4f2b6 Mon Sep 17 00:00:00 2001 From: Nagji Date: Mon, 22 Jul 2024 16:05:16 -0700 Subject: [PATCH 09/10] fix: Remove misc. file --- a.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 a.txt diff --git a/a.txt b/a.txt deleted file mode 100644 index 2d87c7bc..00000000 --- a/a.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 8620b84bb6f23bac9bfbd06153e9b5dd1bd01b4c Mon Sep 17 00:00:00 2001 From: Nagji Date: Mon, 22 Jul 2024 17:14:47 -0700 Subject: [PATCH 10/10] feat: Test Device IR validator and support None max_net_detuning in Program Validator --- .../{device_validators => }/device_ir_validator.py | 0 .../rydberg/validators/program.py | 8 ++++++-- .../device_validators/test_device_ir_validator.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) rename src/braket/analog_hamiltonian_simulator/rydberg/validators/{device_validators => }/device_ir_validator.py (100%) create mode 100644 test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_ir_validator.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/device_ir_validator.py similarity index 100% rename from src/braket/analog_hamiltonian_simulator/rydberg/validators/device_validators/device_ir_validator.py rename to src/braket/analog_hamiltonian_simulator/rydberg/validators/device_ir_validator.py diff --git a/src/braket/analog_hamiltonian_simulator/rydberg/validators/program.py b/src/braket/analog_hamiltonian_simulator/rydberg/validators/program.py index e7afb004..86d7c378 100644 --- a/src/braket/analog_hamiltonian_simulator/rydberg/validators/program.py +++ b/src/braket/analog_hamiltonian_simulator/rydberg/validators/program.py @@ -12,6 +12,7 @@ # language governing permissions and limitations under the License. from copy import deepcopy +from typing import Union from braket.ir.ahs.program_v1 import Program from pydantic.v1 import root_validator @@ -20,13 +21,16 @@ from braket.analog_hamiltonian_simulator.rydberg.validators.capabilities_constants import ( CapabilitiesConstants, ) +from braket.analog_hamiltonian_simulator.rydberg.validators.device_capabilities_constants import ( + DeviceCapabilitiesConstants, +) from braket.analog_hamiltonian_simulator.rydberg.validators.field_validator_util import ( validate_net_detuning_with_warning, ) class ProgramValidator(Program): - capabilities: CapabilitiesConstants + capabilities: Union[CapabilitiesConstants, DeviceCapabilitiesConstants] # The pattern of the shifting field must have the same length as the lattice_sites @root_validator(pre=True, skip_on_failure=True) @@ -61,7 +65,7 @@ def net_detuning_must_not_exceed_max_net_detuning(cls, values): # If no local detuning, we simply return the values # because there are separate validators to validate # the global driving fields in the program - if not len(local_detuning): + if not len(local_detuning) or not capabilities.MAX_NET_DETUNING: return values detuning_times = [ diff --git a/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_ir_validator.py b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_ir_validator.py new file mode 100644 index 00000000..3c4d4e9d --- /dev/null +++ b/test/unit_tests/braket/analog_hamiltonian_simulator/test_validator/validators/device_validators/test_device_ir_validator.py @@ -0,0 +1,13 @@ +import pytest +from pydantic.v1.error_wrappers import ValidationError + +from braket.analog_hamiltonian_simulator.rydberg.validators.device_ir_validator import ( + validate_program, +) + + +def test_validate_program(program_data, capabilities_with_local_rydberg): + try: + validate_program(program=program_data, device_capabilities=capabilities_with_local_rydberg) + except ValidationError as e: + pytest.fail(f"Validate program is failing : {str(e)}")