Source code for braket.default_simulator.operation_helpers

# 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 functools import lru_cache, singledispatch
from typing import Union

import numpy as np

from braket.default_simulator.operation import GateOperation, KrausOperation


[docs] def from_braket_instruction(instruction) -> Union[GateOperation, KrausOperation]: """Instantiates the concrete `GateOperation` or `KrausOperation` object from the specified Braket instruction. Args: instruction: instruction for a circuit specified using the `braket.ir.jacqd` format. Returns: Union[GateOperation, KrausOperation]: instance of the concrete GateOperation or KrausOperation class corresponding to the specified instruction. Raises: NotImplementedError: If no concrete `GateOperation` or `KrausOperation` class has been registered for the instruction type. """ return _from_braket_instruction(instruction)
@singledispatch def _from_braket_instruction(instruction): raise NotImplementedError(f"Instruction {instruction} not recognized")
[docs] @lru_cache() def pauli_eigenvalues(num_qubits: int) -> np.ndarray: """The eigenvalues of Pauli operators and their tensor products. Args: num_qubits (int): the number of qubits the operator acts on Returns: np.ndarray: the eigenvalues of a Pauli product operator of the given size """ if num_qubits == 1: return np.array([1, -1]) return np.concatenate([pauli_eigenvalues(num_qubits - 1), -pauli_eigenvalues(num_qubits - 1)])
[docs] def ir_matrix_to_ndarray(matrix: list[list[list[float]]]) -> np.ndarray: """Converts a JAQCD matrix into a numpy array. Args: matrix (list[list[list[float]]]: The IR representation of a matrix Returns: np.ndarray: The numpy ndarray representation of the matrix """ return np.array([[complex(element[0], element[1]) for element in row] for row in matrix])
[docs] def check_matrix_dimensions(matrix: np.ndarray, targets: tuple[int, ...]) -> None: """Checks that the matrix is of the correct shape to act on the targets. Args: matrix (np.ndarray): The matrix to check targets (tuple[int, ...]): The target qubits the matrix acts on Raises: ValueError: If the matrix is not a square matrix or operates on a space of different dimension than that generated by the target qubits """ if len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]: raise ValueError(f"{matrix} is not a two-dimensional square matrix") dimension = 2 ** len(targets) if dimension != matrix.shape[0]: raise ValueError( f"`matrix` operates on space of dimension {matrix.shape[0]} instead of {dimension}" )
[docs] def check_unitary(matrix: np.ndarray): """Checks that the given matrix is unitary. Args: matrix (np.ndarray): The matrix to check Raises: ValueError: If the matrix is not unitary """ if not np.allclose(np.eye(len(matrix)), matrix.dot(matrix.T.conj())): raise ValueError(f"{matrix} is not unitary")
[docs] def check_hermitian(matrix: np.ndarray): """Checks that the given matrix is Hermitian. Args: matrix (np.ndarray): The matrix to check Raises: ValueError: If the matrix is not Hermitian """ if not np.allclose(matrix, matrix.T.conj()): raise ValueError(f"{matrix} is not Hermitian")
[docs] def check_cptp(matrices: list[np.ndarray]): """Checks that the given matrices define a CPTP map. Args: matrices (list[np.ndarray]): The matrices to check Raises: ValueError: If the matrices do not define a CPTP map """ E = sum([np.matmul(matrix.T.conjugate(), matrix) for matrix in matrices]) if not np.allclose(E, np.eye(*E.shape)): raise ValueError(f"{matrices} do not define a CPTP map")