# 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 numpy as np import pytest from braket.default_simulator import gate_operations, observables from braket.default_simulator.operation_helpers import pauli_eigenvalues testdata_1q = [ (observables.Hadamard, [], gate_operations.RotY([0], -np.pi / 4), pauli_eigenvalues(1), True), (observables.PauliX, [], gate_operations.Hadamard([0]), pauli_eigenvalues(1), True), ( observables.PauliY, [], gate_operations.Unitary([0], np.array([[1, -1j], [1, 1j]]) / np.sqrt(2)), pauli_eigenvalues(1), True, ), (observables.PauliZ, [], None, pauli_eigenvalues(1), True), (observables.Identity, [], None, np.array([1, 1]), False), ( observables.Hermitian, [np.array([[1, 1 - 1j], [1 + 1j, -1]])], gate_operations.Unitary( [0], np.array( [ [-0.45970084 + 0.0j, 0.62796303 - 0.62796303j], [-0.88807383 - 0.0j, -0.32505758 + 0.32505758j], ] ), ), [-np.sqrt(3), np.sqrt(3)], False, ), ] involutory = [ observables.Hadamard([0]), observables.PauliX([0]), observables.PauliY([0]), observables.PauliZ([0]), ] predefined_observables_invalid_targets = [ (observables.Hadamard, [0, 1]), (observables.PauliX, [0, 1]), (observables.PauliY, [0, 1]), (observables.PauliZ, [0, 1]), (observables.Identity, [0, 1]), ] angle = -np.pi / 4 cos_component = np.cos(angle / 2) sin_component = np.sin(angle / 2) h_diag = np.array([[cos_component, -sin_component], [sin_component, cos_component]]) x_diag = np.array([[1, 1], [1, -1]]) / np.sqrt(2) y_diag = np.array([[1, -1j], [1, 1j]]) / np.sqrt(2) @pytest.mark.parametrize( "obs_class, extra_args, expected_gates, eigenvalues, is_standard", testdata_1q ) def test_observable_properties_single_qubit( obs_class, extra_args, expected_gates, eigenvalues, is_standard ): num_qubits = 50 measured_qubits = (20,) observable = obs_class(*extra_args, targets=list(measured_qubits)) actual_gates = observable.diagonalizing_gates(num_qubits) for gate in actual_gates: assert np.allclose(gate.matrix, expected_gates.matrix) assert observable.measured_qubits == measured_qubits if actual_gates: assert observable.targets == measured_qubits else: assert observable.targets == () assert np.allclose(observable.eigenvalues, eigenvalues) assert observable.is_standard == is_standard @pytest.mark.parametrize( "obs_class, extra_args, expected_gates, eigenvalues, is_standard", testdata_1q ) def test_observable_properties_all_qubits( obs_class, extra_args, expected_gates, eigenvalues, is_standard ): num_qubits = 10 # Smaller number so tests run faster observable = obs_class(*extra_args) actual_gates = observable.diagonalizing_gates(num_qubits) for gate in actual_gates: assert np.allclose(gate.matrix, expected_gates.matrix) if actual_gates: assert len(actual_gates) == num_qubits assert not observable.measured_qubits assert not observable.targets @pytest.mark.parametrize("obs", involutory) def test_involutory_powers(obs): for power in range(0, 10, 2): assert (obs**power).__class__ is observables.Identity for power in range(1, 11, 2): assert (obs**power).__class__ is obs.__class__ @pytest.mark.xfail(raises=TypeError) @pytest.mark.parametrize( "obs_class, extra_args, expected_gates, eigenvalues, is_standard", testdata_1q ) def test_power_non_integer(obs_class, extra_args, expected_gates, eigenvalues, is_standard): obs_class(*extra_args, targets=[0]) ** np.pi @pytest.mark.xfail(raises=ValueError) @pytest.mark.parametrize("observable, targets", predefined_observables_invalid_targets) def test_observable_predefined_invalid_targets(observable, targets): observable(targets) @pytest.mark.xfail(raises=ValueError) def test_hermitian_invalid_none_target(): observables.Hermitian(np.eye(4), None) @pytest.mark.xfail(raises=ValueError) def test_hermitian_multi_qubit_fix_qubit(): observables.Hermitian(np.eye(4), [0, 1]).fix_qubit(0) def test_observable_known_diagonalization(): y_diag_expected = np.linalg.multi_dot( [ gate_operations.Hadamard([0]).matrix, gate_operations.S([0]).matrix, gate_operations.PauliZ([0]).matrix, ] ) assert np.allclose(observables.PauliY([0]).diagonalizing_gates()[0].matrix, y_diag_expected) def test_tensor_product_standard(): tensor = observables.TensorProduct( [ observables.Hadamard([1]), observables.PauliX([3]), observables.PauliZ([7]), observables.PauliY([4]), ] ) assert tensor.targets == (1, 3, 4) assert tensor.measured_qubits == (1, 3, 7, 4) assert (tensor.eigenvalues == pauli_eigenvalues(4)).all() assert not tensor.is_standard actual_gates = [gate.matrix for gate in tensor.diagonalizing_gates()] # Z ignored assert len(actual_gates) == 3 assert np.allclose(actual_gates[0], observables.Hadamard([0]).diagonalizing_gates()[0].matrix) assert np.allclose(actual_gates[1], observables.PauliX([0]).diagonalizing_gates()[0].matrix) assert np.allclose(actual_gates[2], observables.PauliY([0]).diagonalizing_gates()[0].matrix) def test_tensor_product_nonstandard(): tensor = observables.TensorProduct( [ observables.Hadamard([1]), observables.Identity([5]), observables.PauliX([3]), observables.PauliZ([7]), observables.PauliY([4]), ] ) assert tensor.targets == (1, 3, 4) assert tensor.measured_qubits == (1, 5, 3, 7, 4) eigenvalues = np.array( [ 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, ] ) assert (tensor.eigenvalues == eigenvalues).all() # Test cached assert (tensor.eigenvalues == eigenvalues).all() actual_gates = [gate.matrix for gate in tensor.diagonalizing_gates()] # Both Identity and Z ignored assert len(actual_gates) == 3 assert np.allclose(actual_gates[0], observables.Hadamard([0]).diagonalizing_gates()[0].matrix) assert np.allclose(actual_gates[1], observables.PauliX([0]).diagonalizing_gates()[0].matrix) assert np.allclose(actual_gates[2], observables.PauliY([0]).diagonalizing_gates()[0].matrix) @pytest.mark.xfail(raises=ValueError) def test_tensor_product_one_component(): observables.TensorProduct([observables.Hadamard([2])]) @pytest.mark.xfail(raises=TypeError) def test_tensor_product_fix_qubit(): observables.TensorProduct([observables.Hadamard([0]), observables.Hadamard([1])]).fix_qubit(0)