| name | hadamard-transform |
| description | A quantum algorithm for performing the Hadamard transform, which is a fundamental operation in quantum computing that creates superposition states. This skill includes efficient implementations and educational resources for understanding and utilizing the Hadamard transform in various quantum algorithms and applications. |
Hadamard Transform
Purpose
The Hadamard Transform ($H^{\otimes n}$) applies a Hadamard gate to every qubit simultaneously, mapping the computational basis to a uniform superposition and vice versa. It is a foundational building block in virtually all quantum algorithms.
Use this skill when you need to:
- Prepare a uniform superposition $\frac{1}{\sqrt{2^n}}\sum_{x=0}^{2^n-1}|x\rangle$ from $|0\rangle^n$.
- Verify the self-inverse property $H^2 = I$ numerically.
- Understand the relationship between QFT and Hadamard transforms.
Overview
The algorithm supports two modes:
'superposition': Applies $H^{\otimes n}$ to $|0\rangle^n$, producing the uniform superposition state. Verifies that all $2^n$ basis states have equal probability $1/2^n$.
'reflexive_test': Initializes a random quantum state $|\psi\rangle$, applies $H^{\otimes n}$ twice, and verifies that the result equals the original state ($H^2 = I$).
Prerequisites
- Basic single-qubit Hadamard gate: $H = \frac{1}{\sqrt{2}}\begin{pmatrix}1&1\1&-1\end{pmatrix}$
- Python:
numpy, Circuit.
Using the Provided Implementation
from unitarylab_algorithms import HadamardTransformAlgorithm
algo = HadamardTransformAlgorithm()
result = algo.run(n=3, mode='superposition', backend='torch')
print(result['status'])
print(result['State vector'])
print(result['Probability distribution'])
print(result['circuit_path'])
result2 = algo.run(n=3, mode='reflexive_test', backend='torch')
print(result2['status'])
Core Parameters Explained
| Parameter | Type | Default | Description |
|---|
n | int | 3 | Number of qubits. Must be $\geq 1$. |
mode | str | 'superposition' | 'superposition' or 'reflexive_test'. |
backend | str | 'torch' | Simulation backend. |
device | str | 'cpu' | Compute device passed to the backend. |
dtype | dtype | np.complex128 | Numeric dtype for the simulation. |
algo_dir | str or None | None | Output directory (set in __init__, not run). |
Common misunderstandings:
'reflexive_test' uses a random initial state generated internally; you cannot supply your own.
'superposition' starts from $|0\rangle^n$ (the default zero state, no explicit preparation needed).
Return Fields
| Key | Type | Description |
|---|
status | str | 'ok' on success, 'failed' otherwise. |
circuit_path | str | Path to the saved SVG circuit diagram. |
plot | list | List of {"format": str, "filename": str} dicts for each saved output file. |
circuit | Circuit | The constructed Circuit object. |
State vector | np.ndarray | Final state vector after the transform. |
Probability distribution | dict | Bitstring → probability (populated for 'superposition' mode; empty dict for 'reflexive_test'). |
Computation time (s) | float | Wall-clock simulation time in seconds. |
Implementation Architecture
HadamardTransformAlgorithm in algorithm.py is intentionally minimal. The run() method sequences five stages directly, with two tiny helper functions for data conversion.
run(n, mode, backend, device, dtype) — Five Stages:
| Stage | Code Action | Algorithmic Role |
|---|
| 1 — Parameter Validation | Checks n >= 1, validates mode string | Guards against invalid inputs |
| 2 — Circuit Construction | Creates Circuit(n, name=...); dispatches on mode: 'superposition' calls _apply_hadamard_layer once; 'reflexive_test' generates random state via numpy and calls qc.initialize(psi, target), then calls _apply_hadamard_layer twice | Builds the transform circuit appropriate to each mode |
| 3 — Simulation | qc.execute(backend=backend, device=device, dtype=dtype) → _as_statevector(raw_result.state) | Runs statevector simulation; wraps result as numpy array |
| 4 — Post-Processing | 'superposition': uses raw_result.probabilities and checks uniformity; 'reflexive_test': computes np.allclose(raw_result.state, original_state) | Verifies algorithm correctness based on mode |
| 5 — Export | self.save_circuit(qc) and self.save_txt() | Saves SVG circuit diagram and text results; returns _build_return_dict() |
Helper Methods:
_apply_hadamard_layer(qc, target_qubits) — Applies qc.h(q) to every qubit in target_qubits. The entire Hadamard transform is just this one loop.
_as_statevector(res) — np.asarray(res, dtype=complex) — converts execute() output to a flat NumPy array.
_probabilities(statevec, threshold) — Computes |amp|² for each basis state; returns a sorted dict of binary-string → float, filtering values below threshold.
_build_return_dict(success, circuit_path, filepath, circuit) — Converts success bool to 'ok'/'failed', packages saved file paths as plot list, and merges self.output fields (State vector, Probability distribution, Computation time (s)) into the returned dict.
Key design note: In 'reflexive_test' mode, the random initial state is generated with numpy and loaded into the circuit via qc.initialize(original_state, target=target_qubits). The state is stored in a local variable original_state for comparison after two H-layer applications.
Data flow (superposition): n → Circuit → _apply_hadamard_layer → execute() → raw_result.probabilities → uniformity check → _build_return_dict().
Data flow (reflexive_test): random psi → qc.initialize(psi) → two _apply_hadamard_layer() calls → execute() → np.allclose(raw_result.state, psi) → _build_return_dict().
Understanding the Key Quantum Components
$$H = \frac{1}{\sqrt{2}}\begin{pmatrix}1&1\1&-1\end{pmatrix}, \quad H|0\rangle = |+\rangle = \frac{|0\rangle+|1\rangle}{\sqrt{2}}, \quad H|1\rangle = |-\rangle = \frac{|0\rangle-|1\rangle}{\sqrt{2}}$$
Tensor Product of $n$ Hadamard Gates
$$H^{\otimes n}|x\rangle = \frac{1}{\sqrt{2^n}}\sum_{y=0}^{2^n-1}(-1)^{x \cdot y}|y\rangle$$
where $x \cdot y = \sum_i x_i y_i \pmod{2}$ is the bitwise inner product.
Superposition State
Starting from $|0\rangle^n$, the transform produces:
$$H^{\otimes n}|0\rangle^n = \frac{1}{\sqrt{2^n}}\sum_{y=0}^{2^n-1}|y\rangle$$
All $2^n$ basis states have equal amplitude $1/\sqrt{2^n}$ and equal probability $1/2^n$.
Self-Inverse Property
$H^\dagger = H$ and $H^2 = I$. Applying $H^{\otimes n}$ twice recovers the original state exactly (up to floating-point precision $\sim 10^{-10}$).
Relationship to QFT
When the input is $|0\rangle^n$, the Hadamard transform equals the Quantum Fourier Transform (QFT), as both produce the uniform superposition.
Theory-to-Code Mapping
| README / Theory Concept | Code Object or Location |
|---|
| $n$-qubit Hadamard transform $H^{\otimes n}$ | _apply_hadamard_layer(qc, target_qubits) — one qc.h(q) per qubit |
| Starting state $ | 0\rangle^n$ |
| Arbitrary initial state (reflexive test) | qc.initialize(original_state, target=target_qubits) |
| Self-inverse property $H^2 = I$ | 'reflexive_test' mode: _apply_hadamard_layer called twice; verified via np.allclose() |
| Uniform output probability $1/2^n$ | Checked in post-processing via np.isclose(p, 1/2^n, atol=1e-5) |
| Bitstring probability dict | _probabilities(state_vector) — converts amplitudes to {bitstring: prob} |
| Status / success | is_success in _build_return_dict(); 'ok' if uniformity/reflexivity test passes |
Notes on encapsulation: This implementation is the simplest in the codebase. The transform itself is entirely realized by qc.h(q) calls inside _apply_hadamard_layer. There is no separate _build_circuit method; circuit construction happens inline in run(). The _probabilities() helper avoids near-zero states using a threshold=1e-12 filter.
Mathematical Deep Dive = \bigotimes_{j=1}^n \frac{|0\rangle + (-1)^{x_j}|1\rangle}{\sqrt{2}}$$
For $|0\rangle^n$:
$$H^{\otimes n}|0\rangle^n = \frac{1}{\sqrt{2^n}}\sum_{y \in {0,1}^n}|y\rangle$$
Norm preservation: $|H^{\otimes n}|x\rangle|^2 = \sum_{y}|(-1)^{x\cdot y}/\sqrt{2^n}|^2 = 2^n \cdot 1/2^n = 1$.
Hands-On Example
from unitarylab_algorithms import HadamardTransformAlgorithm
import numpy as np
algo = HadamardTransformAlgorithm()
result = algo.run(n=4, mode='superposition', backend='torch')
print(f"Number of basis states: {len(result['Probability distribution'])}")
print(f"Each probability: {list(result['Probability distribution'].values())[0]:.6f}")
print(f"Status: {result['status']}")
print(f"Computation time: {result['Computation time (s)']:.4f} s")
result2 = algo.run(n=4, mode='reflexive_test', backend='torch')
print(f"State vector shape: {result2['State vector'].shape}")
Implementing Your Own Version
from unitarylab.core import Circuit
def hadamard_transform(n: int, backend: str = 'torch') -> Circuit:
"""Apply H to all n qubits."""
qc = Circuit(n, name=f"H^{n}")
for q in range(n):
qc.h(q)
return qc
Debugging Tips
- Probability not exactly $1/2^n$: Floating-point arithmetic causes small deviations ($\sim 10^{-15}$). The code uses
np.isclose with atol=1e-5.
- Mode typo: Only
'superposition' and 'reflexive_test' are valid; they are case-sensitive.
'reflexive_test' with $n=1$: Works correctly; the random state is a complex unit vector on the Bloch sphere.
- Expected state includes imaginary parts: $H^{\otimes n}|0\rangle^n$ has only real amplitudes, but the
'reflexive_test' random state will be complex.
- Bit ordering: Probabilities and state vector use little-endian convention (qubit 0 is least significant bit).