Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
The Hadamard test is a quantum circuit that allows estimation of the real and imaginary parts of the expected value of a unitary operator. It is a fundamental subroutine used in many quantum algorithms, including quantum phase estimation and amplitude estimation. The test works by applying a controlled-unitary operation between an auxiliary qubit and the system of interest, with the measurement statistics of the auxiliary qubit encoding information about the unitary's expectation value.

<!--
[metadata-name]: Hadamard Test
[metadata-tags]: Textbook
[metadata-url]: https://github.com/amazon-braket/amazon-braket-algorithm-library/tree/main/src/braket/experimental/algorithms/hadamard_test
-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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.circuits import Circuit, circuit, Instruction


@circuit.subroutine(register=True)
def hadamard_test(controlled_unitary: Circuit, phase: str = 'real') -> Circuit:
"""Implements the Hadamard test circuit for estimating real or imaginary parts
of the expected value of a unitary operator.

Args:
controlled_unitary (Circuit): The unitary operation to be controlled
phase (str): Either 'real' or 'imaginary' to determine which component to estimate

Returns:
Circuit: The complete Hadamard test circuit
"""
if phase not in ['real', 'imaginary']:
raise ValueError("Phase must be either 'real' or 'imaginary'")

circ = Circuit()

circ.h(0)
if phase == 'imaginary':
circ.s(0).adjoint()

# Add control qubit to the unitary circuit
for inst in controlled_unitary.instructions:
targets = [q + 1 for q in inst.target]
controlled_inst = Instruction(
operator=inst.operator,
target=targets,
control=0
)
circ.add_instruction(controlled_inst)

circ.h(0)

return circ
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import numpy as np
import pytest
from braket.circuits import Circuit, ResultType
from braket.devices import LocalSimulator

from braket.experimental.algorithms.hadamard_test.hadamard_test import hadamard_test


def test_hadamard_test_real():
unitary = Circuit().h(0)

test_circuit = hadamard_test(unitary, phase='real')
test_circuit.measure(0)

device = LocalSimulator()
task = device.run(test_circuit, shots=1000)

counts = task.result().measurement_counts
p_zero = counts.get('0', 0) / 1000
real_part = 2 * p_zero - 1

assert np.isclose(real_part, 1/np.sqrt(2), atol=0.1)


def test_hadamard_test_imaginary():
unitary = Circuit().s(0)

test_circuit = hadamard_test(unitary, phase='imaginary')
test_circuit.measure(0)

device = LocalSimulator()
task = device.run(test_circuit, shots=10000)

counts = task.result().measurement_counts
p_zero = counts.get('0', 0) / 10000
imag_part = 2 * p_zero - 1

assert np.isclose(imag_part, 0.0, atol=0.1)


def test_hadamard_test_identity():
unitary = Circuit().i(0)

real_circuit = hadamard_test(unitary, phase='real')
imag_circuit = hadamard_test(unitary, phase='imaginary')
real_circuit.measure(0)
imag_circuit.measure(0)

device = LocalSimulator()

real_task = device.run(real_circuit, shots=1000)
real_counts = real_task.result().measurement_counts
p_zero_real = real_counts.get('0', 0) / 1000
real_part = 2 * p_zero_real - 1

imag_task = device.run(imag_circuit, shots=1000)
imag_counts = imag_task.result().measurement_counts
p_zero_imag = imag_counts.get('0', 0) / 1000
imag_part = 2 * p_zero_imag - 1

assert np.isclose(real_part, 1.0, atol=0.1)
assert np.isclose(imag_part, 0.0, atol=0.1)


@pytest.mark.parametrize("phase", ["real", "imaginary"])
def test_hadamard_test_shots_0(phase):
unitary = Circuit().h(0)
test_circuit = hadamard_test(unitary, phase=phase)
test_circuit.add_result_type(ResultType.Probability(target=[0]))

device = LocalSimulator()
task = device.run(test_circuit, shots=0)

p_zero = task.result().values[0][0]

if phase == 'real':
assert np.isclose(2 * p_zero - 1, 1/np.sqrt(2), atol=0.1)
else:
assert np.isclose(2 * p_zero - 1, 0.0, atol=0.1)


@pytest.mark.xfail(raises=ValueError)
def test_hadamard_test_invalid_phase():
unitary = Circuit().h(0)
hadamard_test(unitary, phase='invalid')