Source code for divi.viz._periodic

# SPDX-FileCopyrightText: 2026 Qoro Quantum Ltd <divi@qoroquantum.de>
#
# SPDX-License-Identifier: Apache-2.0
#
# Attribution: Periodic wrapping follows orqviz (Zapata Engineering, Apache-2.0).
# See LICENSES/ORQViz-Apache-2.0-acknowledgement.txt.

"""Periodic parameter wrapping for variational-program trajectories.

Quantum gate parameters are typically :math:`2\\pi`-periodic.  When an
optimization trajectory crosses the period boundary, PCA can see an
artificial jump and produce distorted landscapes.  The functions here
re-center each parameter vector to its closest periodic copy relative to a
reference point, ensuring continuity along the trajectory.
"""

import numpy as np
import numpy.typing as npt


[docs] def periodic_wrap( point: npt.ArrayLike, reference: npt.ArrayLike, period: float = 2 * np.pi, ) -> npt.NDArray[np.float64]: """Wrap *point* to the closest periodic copy relative to *reference*. For each element, the returned value satisfies ``|wrapped[i] - reference[i]| <= period / 2`` (up to floating-point rounding). This is the element-wise equivalent of ``orqviz``'s ``relative_periodic_wrap``. Args: point: Parameter vector to wrap. reference: Reference parameter vector. period: Periodicity of each parameter. Defaults to :math:`2\\pi`. Returns: Wrapped copy of *point*. """ p = np.asarray(point, dtype=np.float64) r = np.asarray(reference, dtype=np.float64) # Shift so that reference is at zero, wrap into [-period/2, period/2), shift back. diff = (p - r + period / 2) % period - period / 2 return r + diff
[docs] def periodic_trajectory_wrap( trajectory: npt.ArrayLike, period: float = 2 * np.pi, ) -> npt.NDArray[np.float64]: """Unwrap a trajectory so consecutive rows are within half a period. Iterates forward through the rows, wrapping each row relative to its predecessor. The result is a continuous trajectory suitable for PCA. Args: trajectory: Parameter vectors of shape ``(n_steps, n_params)``. period: Periodicity of each parameter. Defaults to :math:`2\\pi`. Returns: Unwrapped copy of *trajectory* with the same shape. Raises: ValueError: If *trajectory* is not 2-D or has fewer than two rows. """ traj = np.asarray(trajectory, dtype=np.float64) if traj.ndim != 2: raise ValueError("trajectory must be a 2-D array of shape (n_steps, n_params).") if traj.shape[0] < 2: raise ValueError("trajectory must contain at least two rows.") out = np.empty_like(traj) out[0] = traj[0] for k in range(1, traj.shape[0]): out[k] = periodic_wrap(traj[k], out[k - 1], period) return out