Source code for autolyap.problemclass.operators

# SPDX-FileCopyrightText: 2025-2026 AutoLyap contributors
# SPDX-License-Identifier: GPL-3.0-only

"""Concrete operator interpolation-condition classes."""

import numpy as np
from typing import List, Union, Tuple

from autolyap.problemclass.base import _OperatorInterpolationCondition
from autolyap.problemclass.indices import _InterpolationIndices
from autolyap.utils.validation import ensure_real_number


[docs] def _ensure_positive_finite(value: Union[int, float], parameter_name: str, error_message: str) -> float: r"""Return `value` as float after enforcing strict positivity and finiteness.""" numeric_value = ensure_real_number(value, parameter_name) if not np.isfinite(numeric_value) or numeric_value <= 0: raise ValueError(error_message) return numeric_value
[docs] def _ensure_finite(value: Union[int, float], parameter_name: str, error_message: str) -> float: r"""Return `value` as float after enforcing finiteness.""" numeric_value = ensure_real_number(value, parameter_name) if not np.isfinite(numeric_value): raise ValueError(error_message) return numeric_value
[docs] class MaximallyMonotone(_OperatorInterpolationCondition): r""" Operator interpolation condition for maximally monotone operators. Let :math:`G: \calH \rightrightarrows \calH` be maximally monotone. - Interpolation inequality: For any :math:`(x_{r_1},u_{r_1}),(x_{r_2},u_{r_2}) \in \operatorname{gra} G`, .. math:: \langle u_{r_1} - u_{r_2}, x_{r_1} - x_{r_2} \rangle \ge 0. - Matrix/vector form used in :doc:`Interpolation conditions </theory/interpolation_conditions>`: With an interpolation vector :math:`z` built from the stacked variables in the inequality above, the same condition is encoded as .. math:: \mathcal{Q}\p{M, z} \le 0, with .. math:: M = \frac{1}{2} \begin{bmatrix} 0 & 0 & -1 & 1 \\ 0 & 0 & 1 & -1 \\ -1 & 1 & 0 & 0 \\ 1 & -1 & 0 & 0 \end{bmatrix}. This condition has no parameters. **References** - :cite:`bauschke2017convexanalysismonotone{Theorem 20.21}`. """ def get_data(self) -> List[Tuple[np.ndarray, _InterpolationIndices]]: r""" Return interpolation data for a maximally monotone operator. The tuple format and notation follow the class-level reference in :class:`~autolyap.problemclass.MaximallyMonotone`. **Returns** - (:class:`~typing.List`\[:class:`~typing.Tuple`\[:class:`numpy.ndarray`, :class:`~autolyap.problemclass.indices._InterpolationIndices`\]\]): A list containing one tuple with the interpolation matrix and indices. """ matrix = 0.5 * np.array([ [0, 0, -1, 1], [0, 0, 1, -1], [-1, 1, 0, 0], [1, -1, 0, 0] ]) interp_idx = _InterpolationIndices("r1<r2") return [(matrix, interp_idx)]
[docs] class StronglyMonotone(_OperatorInterpolationCondition): r""" Operator interpolation condition for strongly and maximally monotone operators. Let :math:`\mu \in \mathbb{R}_{++}` and :math:`G: \calH \rightrightarrows \calH` be :math:`\mu`-strongly monotone. - Interpolation inequality: For any :math:`(x_{r_1},u_{r_1}),(x_{r_2},u_{r_2}) \in \operatorname{gra} G`, .. math:: \langle u_{r_1} - u_{r_2}, x_{r_1} - x_{r_2} \rangle \ge \mu \|x_{r_1} - x_{r_2}\|^2. - Matrix/vector form used in :doc:`Interpolation conditions </theory/interpolation_conditions>`: With an interpolation vector :math:`z` built from the stacked variables in the inequality above, the same condition is encoded as .. math:: \mathcal{Q}\p{M, z} \le 0, with .. math:: M = \frac{1}{2} \begin{bmatrix} 2\mu & -2\mu & -1 & 1 \\ -2\mu & 2\mu & 1 & -1 \\ -1 & 1 & 0 & 0 \\ 1 & -1 & 0 & 0 \end{bmatrix}. **Parameters** - `mu` (:class:`~typing.Union`\[:class:`int`, :class:`float`\]): The strong monotonicity parameter corresponding to :math:`\mu` (must be :math:`> 0` and finite). **Raises** - `ValueError`: If `mu` is not a number, :math:`\le 0`, or infinite. **References** - :cite:`ryu2020operatorsplittingperformance{Proposition 1}`. """ def __init__(self, mu: Union[int, float]) -> None: mu = _ensure_positive_finite( mu, "Strong monotonicity parameter", "Strong monotonicity parameter (mu) must be greater than 0 and finite.", ) self.mu = mu def get_data(self) -> List[Tuple[np.ndarray, _InterpolationIndices]]: r""" Return interpolation data for the strongly monotone operator. The tuple format and notation follow the class-level reference in :class:`~autolyap.problemclass.StronglyMonotone`. **Returns** - (:class:`~typing.List`\[:class:`~typing.Tuple`\[:class:`numpy.ndarray`, :class:`~autolyap.problemclass.indices._InterpolationIndices`\]\]): A list containing one tuple with the interpolation matrix and indices. """ matrix = 0.5 * np.array([ [2 * self.mu, -2 * self.mu, -1, 1], [-2 * self.mu, 2 * self.mu, 1, -1], [-1, 1, 0, 0], [1, -1, 0, 0] ]) interp_idx = _InterpolationIndices("r1<r2") return [(matrix, interp_idx)]
[docs] class LipschitzOperator(_OperatorInterpolationCondition): r""" Operator interpolation condition for Lipschitz operators. Let :math:`L \in \mathbb{R}_{++}` and :math:`G: \calH \to \calH` be :math:`L`-Lipschitz continuous. - Interpolation inequality: For any :math:`x_{r_1}, x_{r_2} \in \calH` with :math:`u_{r_1} = G(x_{r_1})` and :math:`u_{r_2} = G(x_{r_2})`, .. math:: \|u_{r_1} - u_{r_2}\|^2 \le L^2 \|x_{r_1} - x_{r_2}\|^2. - Matrix/vector form used in :doc:`Interpolation conditions </theory/interpolation_conditions>`: With an interpolation vector :math:`z` built from the stacked variables in the inequality above, the same condition is encoded as .. math:: \mathcal{Q}\p{M, z} \le 0, with .. math:: M = \begin{bmatrix} -L^2 & L^2 & 0 & 0 \\ L^2 & -L^2 & 0 & 0 \\ 0 & 0 & 1 & -1 \\ 0 & 0 & -1 & 1 \end{bmatrix}. **Parameters** - `L` (:class:`~typing.Union`\[:class:`int`, :class:`float`\]): The Lipschitz parameter corresponding to :math:`L` (must be :math:`> 0` and finite). **Raises** - `ValueError`: If `L` is not a number, :math:`\le 0`, or infinite. **References** - Kirszbraun--Valentine theorem: :cite:`kirszbraun1934lipschitz`, :cite:`valentine1943extension`, :cite:`valentine1945lipschitzconditionpreserving`. """ def __init__(self, L: Union[int, float]) -> None: L = _ensure_positive_finite( L, "Lipschitz parameter", "Lipschitz parameter (L) must be greater than 0 and finite.", ) self.L = L def get_data(self) -> List[Tuple[np.ndarray, _InterpolationIndices]]: r""" Return interpolation data for the Lipschitz operator. The tuple format and notation follow the class-level reference in :class:`~autolyap.problemclass.LipschitzOperator`. **Returns** - (:class:`~typing.List`\[:class:`~typing.Tuple`\[:class:`numpy.ndarray`, :class:`~autolyap.problemclass.indices._InterpolationIndices`\]\]): A list containing one tuple with the interpolation matrix and indices. """ matrix = np.array([ [-self.L**2, self.L**2, 0, 0], [self.L**2, -self.L**2, 0, 0], [0, 0, 1, -1], [0, 0, -1, 1] ]) interp_idx = _InterpolationIndices("r1<r2") return [(matrix, interp_idx)]
[docs] class Cocoercive(_OperatorInterpolationCondition): r""" Operator interpolation condition for cocoercive operators. Let :math:`\beta \in \mathbb{R}_{++}` and :math:`G: \calH \to \calH` be :math:`\beta`-cocoercive. - Interpolation inequality: For any :math:`x_{r_1}, x_{r_2} \in \calH` with :math:`u_{r_1} = G(x_{r_1})` and :math:`u_{r_2} = G(x_{r_2})`, .. math:: \langle u_{r_1} - u_{r_2}, x_{r_1} - x_{r_2} \rangle \ge \beta \|u_{r_1} - u_{r_2}\|^2. - Matrix/vector form used in :doc:`Interpolation conditions </theory/interpolation_conditions>`: With an interpolation vector :math:`z` built from the stacked variables in the inequality above, the same condition is encoded as .. math:: \mathcal{Q}\p{M, z} \le 0, with .. math:: M = \frac{1}{2} \begin{bmatrix} 0 & 0 & -1 & 1 \\ 0 & 0 & 1 & -1 \\ -1 & 1 & 2\beta & -2\beta \\ 1 & -1 & -2\beta & 2\beta \end{bmatrix}. **Parameters** - `beta` (:class:`~typing.Union`\[:class:`int`, :class:`float`\]): The cocoercivity parameter corresponding to :math:`\beta` (must be :math:`> 0` and finite). **Raises** - `ValueError`: If `beta` is not a number, :math:`\le 0`, or infinite. **References** - :cite:`ryu2020operatorsplittingperformance{Proposition 2}`. """ def __init__(self, beta: Union[int, float]) -> None: beta = _ensure_positive_finite( beta, "Cocoercivity parameter", "Cocoercivity parameter (beta) must be greater than 0 and finite.", ) self.beta = beta def get_data(self) -> List[Tuple[np.ndarray, _InterpolationIndices]]: r""" Return interpolation data for the cocoercive operator. The tuple format and notation follow the class-level reference in :class:`~autolyap.problemclass.Cocoercive`. **Returns** - (:class:`~typing.List`\[:class:`~typing.Tuple`\[:class:`numpy.ndarray`, :class:`~autolyap.problemclass.indices._InterpolationIndices`\]\]): A list containing one tuple with the interpolation matrix and indices. """ matrix = 0.5 * np.array([ [0, 0, -1, 1], [0, 0, 1, -1], [-1, 1, 2 * self.beta, -2 * self.beta], [1, -1, -2 * self.beta, 2 * self.beta] ]) interp_idx = _InterpolationIndices("r1<r2") return [(matrix, interp_idx)]
[docs] class WeakMintyVariationalInequality(_OperatorInterpolationCondition): r""" Operator interpolation condition for operators that fulfill the weak Minty variational inequality. Let :math:`\rho_{\textup{minty}} \in \mathbb{R}` and :math:`G: \calH \rightrightarrows \calH` satisfy a weak Minty variational inequality. - Interpolation inequality: There exists :math:`x_\star \in \calH` with :math:`0 \in G(x_\star)` such that for any :math:`(x_{r_1},u_{r_1}) \in \operatorname{gra} G`, .. math:: \langle u_{r_1}, x_{r_1} - x_\star \rangle \ge \rho_{\textup{minty}} \|u_{r_1}\|^2. - Matrix/vector form used in :doc:`Interpolation conditions </theory/interpolation_conditions>`: With an interpolation vector :math:`z` built from the stacked variables in the inequality above, the same condition is encoded as .. math:: \mathcal{Q}\p{M, z} \le 0, with .. math:: M = \frac{1}{2} \begin{bmatrix} 0 & 0 & -1 & 0 \\ 0 & 0 & 1 & 0 \\ -1 & 1 & 2\rho_{\textup{minty}} & 0 \\ 0 & 0 & 0 & 0 \end{bmatrix}. **Parameters** - `rho_minty` (:class:`~typing.Union`\[:class:`int`, :class:`float`\]): The weak MVI parameter corresponding to :math:`\rho_{\textup{minty}}` (must be finite). **Raises** - `ValueError`: If `rho_minty` is not a number or not finite. **Note** - When used inside :class:`~autolyap.problemclass.InclusionProblem`, the problem must have exactly one component. In the notation of :doc:`3. Algorithm representation </theory/algorithm_representation>`, :math:`m = 1`, :math:`m_{\textup{op}} = 1`, and :math:`m_{\textup{func}} = 0`. This single component may still contain a list of operator conditions (an intersection). """ def __init__(self, rho_minty: Union[int, float]) -> None: rho_minty = _ensure_finite( rho_minty, "Weak MVI parameter", "Weak MVI parameter (rho_minty) must be finite.", ) self.rho_minty = rho_minty def get_data(self) -> List[Tuple[np.ndarray, _InterpolationIndices]]: r""" Return interpolation data for the weak Minty variational inequality condition. The tuple format and notation follow the class-level reference in :class:`~autolyap.problemclass.WeakMintyVariationalInequality`. **Returns** - (:class:`~typing.List`\[:class:`~typing.Tuple`\[:class:`numpy.ndarray`, :class:`~autolyap.problemclass.indices._InterpolationIndices`\]\]): A list containing one tuple with the interpolation matrix and indices. """ matrix = 0.5 * np.array([ [0, 0, -1, 0], [0, 0, 1, 0], [-1, 1, 2 * self.rho_minty, 0], [0, 0, 0, 0] ]) interp_idx = _InterpolationIndices("r1!=star") return [(matrix, interp_idx)]