Möttönen-Vartiainen amplitude-encoding angle computation.
Pure classical preprocessing for the Möttönen amplitude-encoding
construction. Takes an amplitude vector and returns the Gray-walk
Ry (and, for complex inputs, Rz) angle vectors that the
Möttönen Gray-code emission consumes — assuming that the target
register starts in . See
:mod:qamomile.circuit.stdlib.state_preparation.mottonen_amplitude_encoding
for the gate-emission side and the all-zero-state pre-condition.
The math here is intentionally separated from gate emission so it
can also be used standalone — e.g., by hybrid-optimisation loops
that pre-compute angle vectors outside any kernel and then feed
them into mottonen_amplitude_encoding_from_angles via
parameters=[...].
Reference¶
M. Möttönen, J. J. Vartiainen, V. Bergholm, M. M. Salomaa, “Transformation of quantum states using uniformly controlled rotations”, arXiv:quant-ph/0407010 (2004). Equation / section numbers cited in individual function docstrings below refer to this paper. In particular:
The Gray-code decomposition of a
k-control uniformly controlled rotation into2^ksingle-qubit rotations +2^kCNOTs is described in Section II, around Fig. 2 and the paragraph immediately after Eq. (2) (the paper does not number this as a Lemma / Theorem).The angle-basis transform
θ = M^(k) αlinking per-state rotation anglesαto elementary Gray-walk anglesθis Eq. (3) of Section II.Application to state preparation, including the iterative disentangling for general (complex) amplitudes, is in Section III, Eqs. (4)-(8).
Overview¶
| Function | Description |
|---|---|
compute_all_ry_angles_per_level | Pre-compute every level’s Ry rotation angle vector (magnitude stage). |
compute_disentangling_angles_per_level | Iteratively disentangle to obtain both Ry and Rz angles per level. |
compute_mottonen_amplitude_encoding_ry_angles | Pre-compute the flat Ry angle vector for a Möttönen encoding. |
compute_mottonen_amplitude_encoding_rz_angles | Pre-compute the flat Rz angle vector for the phase-restoration stage. |
validate_and_normalize_amplitudes | Validate an amplitude vector and return its normalised form. |
Functions¶
compute_all_ry_angles_per_level [source]¶
def compute_all_ry_angles_per_level(amplitudes: np.ndarray, num_qubits: int) -> list[np.ndarray]Pre-compute every level’s Ry rotation angle vector (magnitude stage).
Implements the recursive magnitude-stage angle formula given in
Möttönen et al., arXiv:quant-ph/0407010, Section III, Eq. (8)
(with the leaf case matching the unnumbered angle
2 \arcsin(|a_{2j}| / \sqrt{|a_{2j-1}|^2 + |a_{2j}|^2})
just before Eq. (6), equivalent to 2 atan2(|a_1|, |a_0|)
on the leaf pair). The pre-condition is the all-zero state
; the formulas below describe the
angles needed to reach a real amplitudes from there.
For each level k (0 <= k < num_qubits) the amplitude
vector is split into 2**k equal chunks. Each chunk yields one
per-control-state angle α (Eq. (8)):
Intermediate levels (
chunk_size > 2): the angle rotates the target qubit so its|1>weight matches the lower-half block norm. Usingarctan2(norm_lower, norm_upper)keeps the formula well defined when the upper half has zero norm.Leaf level (
chunk_size == 2):α = 2 * arctan2(a_1, a_0)directly (signed, so negative amplitudes are preserved without a phase stage).
For k >= 1 the per-control-state angles are then transformed
to the Gray-walk basis via :func:_to_gray_walk_basis (paper
Eq. (3)).
Parameters:
| Name | Type | Description |
|---|---|---|
amplitudes | np.ndarray | Unit-norm real amplitude vector of length 2**num_qubits. |
num_qubits | int | Number of qubits in the target register. |
Returns:
list[np.ndarray] — list[np.ndarray]: A list of num_qubits arrays; the k-th
entry has length 2**k and holds the Gray-walk Ry
angles for that level.
compute_disentangling_angles_per_level [source]¶
def compute_disentangling_angles_per_level(
amplitudes: np.ndarray,
num_qubits: int,
) -> tuple[list[np.ndarray], list[np.ndarray]]Iteratively disentangle to obtain both Ry and Rz angles per level.
Implements the Möttönen disentangling sweep for general (complex)
amplitudes from Möttönen et al., arXiv:quant-ph/0407010,
Section III, Eqs. (4)-(8): the phase-equalisation rotation
Ξ_z (Eq. (4)) followed by the magnitude rotation, applied
pair-by-pair from LSB to MSB. Pre-condition is the all-zero
state ; the angles below are
those needed to reach the input amplitudes from there
(computed via the inverse sweep that disentangles the input).
At each step the amplitude vector is halved by pairing adjacent
entries; for the pair (a_0, a_1) we read off
Ry angle = 2 * arctan2(|a_1|, |a_0|)(magnitude split, paper Eq. (8) restricted to the leaf level — equivalently the unnumbered2 arcsin(...)form just before Eq. (6)),Rz angle = arg(a_1 / a_0)(phase difference, paper Eq. (5)),
and replace the pair with the single complex amplitude that
survives the implicit Rz^{-1} Ry^{-1} disentangling step
(paper Eq. (6) zeros out one of the pair entries; the
surviving amplitude is
which carries the averaged phase needed by the next outer step
of the sweep — the paper does not write β in this exact
closed form but the relation falls out of combining
Eqs. (5)-(7)). The full sweep is paper Eq. (7).
Zero-magnitude halves are handled gracefully by leaving the
corresponding angle at 0 (the underlying state has no support
there so the angle is immaterial). The returned per-level arrays
are already bit-reversed and gray-walk-transformed (paper
Eq. (3) applied per level via :func:_to_gray_walk_basis),
ready for the Möttönen Gray-walk emission.
Parameters:
| Name | Type | Description |
|---|---|---|
amplitudes | np.ndarray | Unit-norm complex amplitude vector of length 2**num_qubits. |
num_qubits | int | Number of qubits in the target register. |
Returns:
tuple[list[np.ndarray], list[np.ndarray]] — tuple[list[np.ndarray], list[np.ndarray]]:
(ry_angles_per_level, rz_angles_per_level) in
Gray-walk ordering. Each list has num_qubits entries;
the k-th entry holds 2**k angles for level k of
the forward emission.
compute_mottonen_amplitude_encoding_ry_angles [source]¶
def compute_mottonen_amplitude_encoding_ry_angles(amplitudes: Sequence[float] | Sequence[complex] | np.ndarray) -> np.ndarrayPre-compute the flat Ry angle vector for a Möttönen encoding.
Returns the Gray-walk Ry angles for the magnitude stage of the
encoding. For real inputs (or complex inputs with zero imaginary
part) this corresponds to the single-stage signed-Ry encoding.
For complex inputs with non-zero imaginary part, these are the
magnitude-stage angles only — pair with
:func:compute_mottonen_amplitude_encoding_rz_angles to obtain
the phase-stage angles needed to reproduce the full complex
state.
Parameters:
| Name | Type | Description |
|---|---|---|
amplitudes | Sequence[float] | Sequence[complex] | np.ndarray | Amplitude vector of length 2**n. Real or complex; it is normalised automatically. |
Returns:
np.ndarray — np.ndarray: 1-D array of length 2**n - 1 holding the
Gray-walk Ry angles laid out level by level.
Raises:
ValueError— If the input is not a 1-D vector, the length is not a power of two (or is less than 2, i.e., would map to a zero-qubit register), or all amplitudes are zero.
compute_mottonen_amplitude_encoding_rz_angles [source]¶
def compute_mottonen_amplitude_encoding_rz_angles(amplitudes: Sequence[float] | Sequence[complex] | np.ndarray) -> np.ndarrayPre-compute the flat Rz angle vector for the phase-restoration stage.
Returns the Gray-walk Rz angles for the phase stage of the
Möttönen encoding. For real inputs (or complex inputs with zero
imaginary part) the phase stage is unnecessary and the returned
array is all zeros. For complex inputs with non-zero imaginary
part, the returned angles together with the Ry angles from
:func:compute_mottonen_amplitude_encoding_ry_angles reproduce
the full complex state.
Parameters:
| Name | Type | Description |
|---|---|---|
amplitudes | Sequence[float] | Sequence[complex] | np.ndarray | Amplitude vector of length 2**n. Real or complex; it is normalised automatically. |
Returns:
np.ndarray — np.ndarray: 1-D array of length 2**n - 1 holding the
Gray-walk Rz angles laid out level by level (all zeros for
real inputs).
Raises:
ValueError— If the input is not a 1-D vector, the length is not a power of two (or is less than 2, i.e., would map to a zero-qubit register), or all amplitudes are zero.
validate_and_normalize_amplitudes [source]¶
def validate_and_normalize_amplitudes(
amplitudes: Sequence[float] | Sequence[complex] | np.ndarray,
) -> tuple[np.ndarray, int, bool]Validate an amplitude vector and return its normalised form.
The Möttönen construction (arXiv:quant-ph/0407010, Section III) works on a unit-norm amplitude vector indexed by computational basis states; this helper enforces that pre-condition so the downstream angle computation can assume a well-formed input.
Inputs may be real or complex. A complex input whose imaginary
part is identically zero (within np.allclose tolerance) is
coerced to a real array; this preserves the cheaper signed-RY fast
path for vectors that happen to arrive boxed as complex.
Parameters:
| Name | Type | Description |
|---|---|---|
amplitudes | Sequence[float] | Sequence[complex] | np.ndarray | Amplitude vector. Must be a 1-D sequence whose length is a power of two and at least 2, with at least one non-zero entry. |
Returns:
tuple[np.ndarray, int, bool] — tuple[np.ndarray, int, bool]:
(normalized, num_qubits, is_complex) where
normalized is a unit-norm np.ndarray,
num_qubits is log2(len(amplitudes)), and
is_complex is True iff the input has a non-zero
imaginary component (and therefore needs the
phase-restoration stage downstream). When is_complex
is False, normalized.dtype is float; otherwise
it is complex.
Raises:
ValueError— If the input is not a 1-D vector (e.g., a nested sequence or a 2-Dnp.ndarray), the length is not a power of two (or is less than 2, i.e., would map to a zero-qubit register), or all amplitudes are zero.