Source code for braket.analog_hamiltonian_simulator.rydberg.validators.atom_arrangement

# 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.

import warnings
from decimal import Decimal

import numpy as np
from braket.ir.ahs.atom_arrangement import AtomArrangement
from pydantic.v1.class_validators import root_validator

from braket.analog_hamiltonian_simulator.rydberg.validators.capabilities_constants import (
    CapabilitiesConstants,
)


def _euclidean_distance(
    site_1: tuple[Decimal, Decimal], site_2: tuple[Decimal, Decimal]
) -> Decimal:
    # Compute the Euclidean distance between two sets of 2-D points, (x1, y1) and (x2, y2)

    return np.linalg.norm(np.array(site_1) - np.array(site_2))


[docs] class AtomArrangementValidator(AtomArrangement): capabilities: CapabilitiesConstants # Each site has two coordinates (minItems=maxItems=2)
[docs] @root_validator(pre=True, skip_on_failure=True) def sites_have_length_2(cls, values: dict) -> dict: """ Validate that the sites in the atom arrangement have only two coordinates Args: values (Dict): The site and capability constants Returns: Dict: The validated sites """ sites = values["sites"] capabilities = values["capabilities"] for index, site in enumerate(sites): if len(site) != capabilities.DIMENSIONS: raise ValueError( f"Site {index}({site}) has length {len(site)}; it must be " f"{capabilities.DIMENSIONS}." ) return values
# All lattice sites should fit within a (BOUNDING_BOX_SIZE_X) x (BOUNDING_BOX_SIZE_Y) # bounding box. If not, a warning message will issue to remind the user that the SI # units are used here.
[docs] @root_validator(pre=True, skip_on_failure=True) def sites_fit_in_bounding_box(cls, values): sites = values["sites"] if sites: capabilities = values["capabilities"] sorted_sites = sorted(sites, key=lambda xy: xy[0]) biggest_x_distance = sorted_sites[-1][0] - sorted_sites[0][0] if biggest_x_distance > capabilities.BOUNDING_BOX_SIZE_X: warnings.warn( f"Sites {sorted_sites[0]} and {sorted_sites[-1]} " "have x-separation bigger than the typical scale " f"({capabilities.BOUNDING_BOX_SIZE_X} meters). " "The coordinates of the atoms should be specified in SI units." ) if biggest_x_distance <= capabilities.BOUNDING_BOX_SIZE_X: sorted_sites = sorted(sites, key=lambda xy: xy[1]) biggest_y_distance = sorted_sites[-1][1] - sorted_sites[0][1] if biggest_y_distance > capabilities.BOUNDING_BOX_SIZE_Y: warnings.warn( f"Sites {sorted_sites[0]} and {sorted_sites[-1]} " "have y-separation bigger than the typical scale " f"({capabilities.BOUNDING_BOX_SIZE_Y} meters). " "The coordinates of the atoms should be specified in SI units." ) return values
# Filling has only integers which are either 0 or 1
[docs] @root_validator(pre=True, skip_on_failure=True) def filling_contains_only_0_and_1(cls, values): filling = values["filling"] for idx, f in enumerate(filling): if f not in {0, 1}: raise ValueError(f"Invalid value at {idx} (value: {f}). Only 0 and 1 are allowed.") return values
# Filling must have the same length as `lattice_sites`.
[docs] @root_validator(pre=True, skip_on_failure=True) def filling_same_length_as_sites(cls, values): filling = values["filling"] expected_length = len(values["sites"]) length = len(filling) if length != expected_length: raise ValueError( f"Filling length ({length}) does not match sites length ({expected_length})" ) return values
# Two lattice sites cannot be closer (in terms of Euclidean distance) than MIN_DISTANCE
[docs] @root_validator(pre=True, skip_on_failure=True) def sites_not_too_close(cls, values): sites = values["sites"] capabilities = values["capabilities"] for index_1, site_1 in enumerate(sites): for index_2, site_2 in enumerate(sites[index_1 + 1 :], start=index_1 + 1): distance = _euclidean_distance(site_1, site_2) if distance < capabilities.MIN_DISTANCE: warnings.warn( f"Sites {index_1}({site_1}) and site {index_2}({site_2}) are too close. " f"Their Euclidean distance ({Decimal(str(distance))} meters) is smaller " f"than the typical scale ({capabilities.MIN_DISTANCE} meters). " "The coordinates of the sites should be specified in SI units." ) return values