Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

qamomile.linalg.mottonen

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 0n|0\rangle^{\otimes n}. 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:

Overview

FunctionDescription
compute_all_ry_angles_per_levelPre-compute every level’s Ry rotation angle vector (magnitude stage).
compute_disentangling_angles_per_levelIteratively disentangle to obtain both Ry and Rz angles per level.
compute_mottonen_amplitude_encoding_ry_anglesPre-compute the flat Ry angle vector for a Möttönen encoding.
compute_mottonen_amplitude_encoding_rz_anglesPre-compute the flat Rz angle vector for the phase-restoration stage.
validate_and_normalize_amplitudesValidate 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 0n|0\rangle^{\otimes n}; 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)):

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:

NameTypeDescription
amplitudesnp.ndarrayUnit-norm real amplitude vector of length 2**num_qubits.
num_qubitsintNumber 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 0n|0\rangle^{\otimes n}; 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

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

β=a02+a12exp ⁣(iarga0+arga12),\beta = \sqrt{|a_0|^2 + |a_1|^2} \, \exp\!\left(i\,\frac{\arg a_0 + \arg a_1}{2}\right),

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:

NameTypeDescription
amplitudesnp.ndarrayUnit-norm complex amplitude vector of length 2**num_qubits.
num_qubitsintNumber 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.ndarray

Pre-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:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude 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:


compute_mottonen_amplitude_encoding_rz_angles [source]

def compute_mottonen_amplitude_encoding_rz_angles(amplitudes: Sequence[float] | Sequence[complex] | np.ndarray) -> np.ndarray

Pre-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:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude 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:


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:

NameTypeDescription
amplitudesSequence[float] | Sequence[complex] | np.ndarrayAmplitude 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: