> ## Documentation Index
> Fetch the complete documentation index at: https://prod-mint.classiq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Hadamard Test

<Card title="View on GitHub" icon="github" href="https://github.com/Classiq/classiq-library/blob/main/algorithms/quantum_primitives/hadamard_test/hadamard_test.ipynb">
  Open this notebook in GitHub to run it yourself
</Card>

The Hadamard test \[[1](#childs)] is a widely-used \[[2](#article-1),[3](#article-2)] quantum primitive that provides an elegant method to compute the real part of an expectation value of a given unitary for some target state.

Many problems require evaluating the expectation value of a unitary operator for a prepared state, and the Hadamard test offers an intuitive alternative to the traditional methods of decomposing the unitary into Pauli strings and measuring each non-commutative string independently.

The Hadamard test is a special case of the [linear combination of unitaries](https://github.com/Classiq/classiq-library/blob/main/tutorials/basic_tutorials/quantum_primitives/linear_combination_of_unitaries/linear_combination_of_unitaries.ipynb) (LCU) primitive.

The [SWAP test](https://github.com/Classiq/classiq-library/blob/main/algorithms/quantum_primitives/swap_test/swap_test.ipynb), another special case of the LCU, may be viewed as a variation of the Hadamard test.

The overall implementation consists of three functional building blocks followed by a measurement step, as illustrated in the scheme below:

<center>
  <img src="https://docs.classiq.io/resources/hadamard_new_blocks.png" alt="hadamard_test_blocks" border="0" />
</center>

To implement the Hadamard test algorithm with a unitary $U$ and target state $|{\psi}\rangle$ as inputs and control-qubit probabilities as the outputs, a Hadamard gate $H$ is first applied to place the control qubit in a uniform superposition $\frac{1}{\sqrt{2}}\big(|{0}\rangle|{\psi}\rangle+|{1}\rangle|{\psi}\rangle\big)$. Next, a controlled unitary gate is applied to the target qubit array, resulting in the state $\frac{1}{\sqrt{2}}\big(|{0}\rangle|{\psi}\rangle+|{1}\rangle U|{\psi}\rangle\big)$.

Another Hadamard gate $H$ is then applied to the control qubit, yielding $\frac{1}{2}\big(|{0}\rangle\big(\mathbb{I}+U\big)|{\psi}\rangle+|{1}\rangle\big(\mathbb{I}-U\big)|{\psi}\rangle\big)$, after which a final measurement is performed on the control qubit.

The probability of measuring the control qubit in state $|{0}\rangle$, given by $P(0)=||\frac{1}{2}\big(\mathbb{I}+U\big)|{\psi}\rangle||^2$, enables the calculation the real part of the expectation value $\langle\psi|U|\psi\rangle$ in a post-processing step, through the simple algebraic operation $\text{Re}\langle\psi|U|\psi\rangle=2P(0)-1$. A different algebraic operation can be used to retrieve the imaginary part of the expectation value.

You can refer to the Technical Details section below, describing the full mathematical derivation of a general Hadamard test implementation.

In this tutorial, we will implement a Hadamard test for the Quantum Fourier Transform (QFT) unitary $U_{QFT}$ ([read more](https://docs.classiq.io/latest/explore/functions/qmod_library_reference/classiq_open_library/qft/qft/)), acting on a 4-qubit target state $|0000\rangle$ using the Classiq IDE/ SDK.

This implementation leverages Classiq's high-level functional design utilities, following the functional block structure outlined above.

<Accordion title="NOTE: Quantum Fourier Transform">
  The Quantum Fourier Transform (QFT) function is the quantum analog for the discrete Fourier transform. It is applied on the quantum register state vector in the following manner:

  $$
  U_{QFT}|{j}\rangle=\frac{1}{\sqrt{2^n}}\sum_{k=0}^{2^n-1}e^{\frac{2\pi i}{2^n}jk}|{k}\rangle=\otimes_{t=1}^n\frac{1}{\sqrt{2}}\big(|{0}\rangle+e^{\frac{2\pi i}{2^{t}}j}|{1}\rangle)
  $$

  Where $j$ and $k$ are the binary numbers the $n$ qubits represent. [more information](https://docs.classiq.io/latest/explore/functions/qmod_library_reference/classiq_open_library/qft/qft/)
</Accordion>

## Guided Implementation

To implement the Hadamard test for the QFT unitary $U_{QFT}$ and the state $|0000\rangle$, one control qubit and an array of four target qubits are initialized.

The control qubit variable will be named `expectation_value` and is of `QBit` type, and the target qubit array will be captured by the `QArray` type variable `psi`.

All qubits are initialized in $|0\rangle$ states, and the state of the `psi` qubit array will remain unchanged throughout the implementation ($|0000\rangle$).

Our implementation of the Hadamard test involves three main steps, followed by a measurement of the `expectation_value` qubit and a post-processing step to obtain the real part of the expectation value:

1. Applying the Hadamard gate $H$ to the `expectation_value` qubit as a preparation step, creating a uniform superposition.

2. Applying the unitary gate $U_{QFT}$ on the `psi` qubit array in a controlled manner, conditioned on the control qubit being in the $|{1}\rangle$ state.

3. Re-application of a Hadamard gate $H$ to the control qubit that can be seen as an inverse preparation step, with $H$ acting as its own inverse.

4. A projective measurement of the `expectation_value` qubit, yielding the probabilities of measuring it in the $|0\rangle$ and $|1\rangle$ states.

The probability $P(0)$ of being in the $|0\rangle$ state is then algebraically manipulated in a post-processing step to yield the real part of the expectation value by using the expression $2P(0)-1$.

We begin by defining the function `controlled_qft` that implements the controlled operation of the unitary $U_{QFT}$ on `psi`, conditioned on the control qubit `expectation_value` is in the $|{1}\rangle$ state.

This is achieved by leveraging the Classiq built-in `control` and `qft` functions:

```python theme={null}
from classiq import *


@qfunc
def controlled_qft(expectation_value: QBit, psi: QArray):
    control(expectation_value, lambda: qft(psi))
```

Next, We define the function `preparation_and_application`, seamlessly implementing the three main steps of the Hadamard test as outlined above, using the Classiq `Within-Apply` statement ([read more](https://docs.classiq.io/latest/qmod-reference/language-reference/statements/within-apply/)).

The `Within-Apply` statement performs the operation $V^{\dagger}UV$, specifically designed for situations where a preparation step is performed solely to enable the operation of a particular function and is subsequently inverted.

The preparation and inverse-preparation actions should be specified within the `Within` section, while the primary function operating should be specified in the `Apply` section.

Since the third step, which involves the re-application of the Hadamard gate to the `expectation_value` qubit can be regarded as an inverse-preparation step (due to $H$ being its own inverse), the Hadamard test becomes a natural candidate for the `Within-Apply` statement.

The preparation stage, which involves applying a Hadamard gate $H$ to the `expectation_value` qubit, and the re-application of the Hadamard gate to the same qubit after the controlled QFT operation on the `psi` qubit array are both managed within the `Within` section.

The function `controlled_qft`, which handles the controlled operation of $U_{QFT}$ on the `psi` qubit array, is specified in the `Apply` section:

```python theme={null}
@qfunc
def preparation_and_application(expectation_value: QBit, psi: QArray):
    within_apply(
        within=lambda: H(expectation_value),
        apply=lambda: controlled_qft(expectation_value, psi),
    )
```

Finally, we define a `main` function that encapsulates all essential components of the algorithm. It begins with the declaration and initialization of all qubits, followed by a call to the `preparation_and_application` function, which implements the three core steps:

```python theme={null}
@qfunc
def main(expectation_value: Output[QBit]):
    psi = QArray("psi")
    allocate(out=expectation_value, num_qubits=1)
    allocate(out=psi, num_qubits=4)
    preparation_and_application(expectation_value, psi)
    drop(psi)


qmod = create_model(main)
qprog = synthesize(qmod)
show(qprog)
```

<Info>
  **Output:**

  ```

  Quantum program link: https://platform.classiq.io/circuit/3A5AYyLkEMaECzD13g89cDx7jqo
    

  ```
</Info>

While the code is elegantly structured, the resulting quantum program could be highly complex.

The Classiq synthesis engine expertly manages this complexity, transforming the high-level code into a fully optimized quantum circuit according to your optimization preferences.

<center>
  <img src="https://docs.classiq.io/resources/hadamard_new_vid.gif" alt="gif showing the expansion of the different building blocks" border="0" />
</center>

By declaring `psi` as a local variable in the `main` function (in contrast to `expectation_value`, which is declared globally), the execution of the quantum program on the Classiq simulator will yield the measurement outcomes of the `expectation_value` qubit in states $|{0}\rangle$ and $|{1}\rangle$, along with the corresponding measurement probabilities.

The probability $P(0)$ can then be algebraically manipulated to calculate the real part of the expectation value, which should align with the analytical result:

$$
\text{Re}\big(\langle 0000|U_{qft}|0000\rangle\big)=\langle 0000|++++\rangle= 0.25
$$

You can refer to the note below for the complete derivation.

<Accordion title="Complete derivation">
  After the execution of the `main` function, the system is evolved into its final quantum state:

  $$
  \frac{1}{2}\Big(|{0}\rangle\big(\mathbb{I}+U_{QFT}\big)|{0000}\rangle+|{1}\rangle\big(\mathbb{I}-U_{QFT}\big)|{0000}\rangle\Big)=\frac{1}{2}\Big(|{0}\rangle\big(|{0000}\rangle+|{++++}\rangle\big)+|{1}\rangle\big(|{0000}\rangle-|{++++}\rangle\big)\Big)
  $$

  Since applying QFT on $|{0000}\rangle$ is equivalent to applying a 4-qubit Hadamard transform, transforming it to the  $|{++++}\rangle$ state.

  Running the program on the Classiq simulator outputs the measurement results for both states of the control qubits, which can be analytically calculated and compared:

  $$
  P(0)=\frac{1}{4}|||{0000}\rangle+|{++++}\rangle||^2=\frac{1}{2}\big(1+\frac{1}{4}\big)=0.625,\;\;\;\;\;\;\;\;  P(1)=\frac{1}{4}|||{0000}\rangle-|{++++}\rangle||^2=\frac{1}{2}\big(1-\frac{1}{4}\big)=0.375
  $$

  where the result of the inner product $\langle 0000|++++\rangle=\frac{1}{4}\langle 0000|0000\rangle=\frac{1}{4}$ is used.

  The probabilities can then be manipulated to calculate the expectation value as $\text{Re}\big(\langle 0000|U_{qft}|0000\rangle\big)=2P(0)-1=0.25$, yielding the same result as the direct calculation provided above in the main text.
</Accordion>

Now, let us verify this by executing the quantum program and comparing the results with the analytical (pen-and-paper) calculations we have just derived.

This could be achieved by executing manually through the IDE, selecting the Classiq simulator as execution hardware, and setting `Num shots` to "100000":

<center>
  <img src="https://docs.classiq.io/resources/hadamard_execution.gif" alt="gif execution of the Hadamard test using the Classiq simulator" border="0" width="750" height="auto" />
</center>

Or through the SDK, by running the following code:

```python theme={null}
tot_num_shots = 100000
qmod_with_execution_preferences = set_execution_preferences(
    qmod, num_shots=tot_num_shots
)
qprog_with_execution_preferences = synthesize(qmod_with_execution_preferences)
job = execute(qprog_with_execution_preferences)

results = job.result()[0].value.counts
P_0 = (results["0"]) / tot_num_shots
P_1 = (results["1"]) / tot_num_shots
print(r"P_0={}".format(P_0))
print(r"P_1={}".format(P_1))
```

<Info>
  **Output:**

  ```

  P_0=0.62452
    P_1=0.37548
    

  ```
</Info>

Execution through the SDK enables post-processing of the data, allowing us to recover the real part of the expectation value and compare it to the analytically calculated value:

```python theme={null}
Expectation_value = 2 * P_0 - 1
print("Re(<U>)={}".format(Expectation_value))
```

<Info>
  **Output:**

  ```

  Re(<U>)=0.24903999999999993
    

  ```
</Info>

The value obtained is a statistical estimate derived from averaging measurement outcomes, where the number of measurements (`tot_num_shots`) determines the precision of this estimate.

## Technical Details

The following mathematical description is for an implementation of a Hadamard test on a system of one control qubit and a target qubit-array of $N$ qubits, initiated in $|{0}\rangle|{\psi}\rangle$, where $|{\psi}\rangle$ may essentially be in any prepared state.

The control qubit is first prepared in a uniform superposition by applying a Hadamard transform $H$:

$$
|{\phi_1}\rangle=\big(H\otimes\mathbb{I}\big)|{0}\rangle|{\psi}\rangle= \frac{1}{\sqrt{2}}\Big(|{0}\rangle|{\psi}\rangle+|{1}\rangle|{\psi}\rangle\Big) \qquad\qquad;\qquad\qquad H=\frac{1}{\sqrt{2}}\left( {\begin{array}{cc}
   1 & 1 \\
   1 & -1 \\
  \end{array} } \right)
$$

This step is sequentially followed by a selection step, in which a controlled unitary operation of the form $V=|{0}\rangle\langle{0}|\otimes \mathbb{I}+|{1}\rangle\langle{1}|\otimes U$ is successively applied to the target qubit(s), where $U$ is some general unitary matrix:

$$
|{\phi_2}\rangle=V|{\phi_1}\rangle= |{0}\rangle U|{\psi}\rangle+|{1}\rangle|{\psi}\rangle
$$

Another Hadamard transform is then applied to the control qubit:

$$
|{\phi_3}\rangle=\big(H\otimes\mathbb{I}\big)|{\phi_2}\rangle= \frac{1}{2}\Big(|{0}\rangle|{\psi}\rangle+|{1}\rangle|{\psi}\rangle+|{0}\rangle U|{\psi}\rangle-|{1}\rangle U|{\psi}\rangle\Big)=\frac{1}{2}\Big(|{0}\rangle\big(\mathbb{I}+U\big)|{\psi}\rangle+|{1}\rangle\big(\mathbb{I}-U\big)|{\psi}\rangle\Big)
$$

The final step, prior to the post-processing algebraic manipulation, is a projective measurement of the control (ancilla) qubit onto the $|{0}\rangle$ subspace $\mathcal{P}=|{0}\rangle\langle{0}|\otimes\mathbb{I}$:

$$
|{\phi_4}\rangle=\mathcal{P}|{\phi_3}\rangle=\big(|{0}\rangle\langle{0}|\otimes\mathbb{I}\big)|{\phi_3}\rangle=\frac{1}{2}|{0}\rangle\big(\mathbb{I}+U\big)|{\psi}\rangle
$$

This measurement is effectively translated into a measurement of the expectation value $\text{Re}\big(\langle{\psi}|U|{\psi}\rangle\big)$ by first obtaining the probability that the control qubit is in the $|{0}\rangle$ state:

$$
P(0)=||\frac{1}{2}\big(\mathbb{I}+U\big)|{\psi}\rangle||^2=\frac{1}{4}\langle{\psi}|\big(\mathbb{I}+U^\dagger\big)\big(\mathbb{I}+U\big)|{\psi}\rangle=\frac{1}{4}\Big(\langle{\psi}|{\psi}\rangle+\langle{\psi}|U^\dagger|{\psi}\rangle+\langle{\psi}|U|{\psi}\rangle+\langle{\psi}|UU^\dagger|{\psi}\rangle\Big)=\frac{1}{4}\Big(2+\langle{\psi}|U^\dagger|{\psi}\rangle+\langle{\psi}|U|{\psi}\rangle\Big)
$$

And algebraically manipulating it to receive the real part of the expectation value of $U$:

$$
2P(0)-1=\frac{1}{2}\Big(2+\langle{\psi}|U^\dagger|{\psi}\rangle+\langle{\psi}|U|{\psi}\rangle\Big)-1=\frac{1}{2}\Big(\langle{\psi}|U^\dagger|{\psi}\rangle+\langle{\psi}|U|{\psi}\rangle\Big)=\frac{1}{2}\Big(\big(\langle{\psi}|U|{\psi}\rangle\big)^\dagger+\langle{\psi}|U|{\psi}\rangle\Big)=\text{Re}\big(\langle{\psi}|U|{\psi}\rangle\big)
$$

## References

<a id="childs">\[1]</a>: [Lecture Notes on
Quantum Algorithms (Andrew M. Childs)](https://www.cs.umd.edu/~amchilds/qa/)

<a id="article-1">\[2]</a>: [Quantum error mitigation for Fourier moment computation (Kiss et al.)](https://arxiv.org/pdf/2401.13048)

<a id="article-2">\[3]</a>: [Quantum-classical algorithms for skewed linear systems with an optimized Hadamard test
(Wu et al.)](https://arxiv.org/abs/2009.13288)
