Source code for ellalgo.oracles.lmi_old_oracle

from typing import List, Optional, Tuple

import numpy as np

from ellalgo.cutting_plane import OracleFeas
from ellalgo.oracles.ldlt_mgr import LDLTMgr

Cut = Tuple[np.ndarray, float]


[docs] class LMIOldOracle(OracleFeas): """Oracle for Linear Matrix Inequality constraint. This oracle solves the following feasibility problem: find x s.t. (B − F * x) ⪰ 0 This is a legacy implementation that constructs the full LMI matrix explicitly. For better performance with large matrices, use `LMIOracle` which uses lazy evaluation. Examples: >>> import numpy as np >>> from ellalgo.oracles.lmi_old_oracle import LMIOldOracle >>> F1 = np.array([[1.0, 0.0], [0.0, 1.0]]) >>> F2 = np.array([[0.0, 1.0], [1.0, 0.0]]) >>> B = np.array([[2.0, 0.0], [0.0, 2.0]]) >>> oracle = LMIOldOracle([F1, F2], B) >>> result = oracle.assess_feas(np.array([0.0, 0.0])) >>> result is None or isinstance(result, tuple) True """ def __init__(self, mat_f: List[np.ndarray], mat_b: np.ndarray): """Initialize the LMI oracle with coefficient matrices. :param mat_f: List of coefficient matrices [F₁, F₂, ..., Fₙ] where each F_i ∈ ℝ^{m×m} :param mat_b: Constant matrix B ∈ ℝ^{m×m} defining the LMI constraint """ self.mat_f = mat_f self.mat_f0 = mat_b self.ldlt_mgr = LDLTMgr(len(mat_b))
[docs] def assess_feas(self, xc: np.ndarray) -> Optional[Cut]: """Assess the feasibility of a candidate solution. This method checks if the given solution satisfies the LMI constraint (B − F₁x₁ − F₂x₂ − ... − Fₙxₙ) ⪰ 0 by constructing the full matrix and performing LDLT factorization. :param xc: The candidate solution vector x :returns: `None` if feasible, otherwise a tuple `(g, ep)` containing the subgradient `g` and the negative eigenvalue measure `ep` :raises: None Examples: >>> import numpy as np >>> from ellalgo.oracles.lmi_old_oracle import LMIOldOracle >>> F1 = np.array([[1.0, 0.0], [0.0, 1.0]]) >>> F2 = np.array([[0.0, 1.0], [1.0, 0.0]]) >>> B = np.array([[2.0, 0.0], [0.0, 2.0]]) >>> oracle = LMIOldOracle([F1, F2], B) >>> oracle.assess_feas(np.array([0.0, 0.0])) is None True """ n = len(xc) A = self.mat_f0.copy() A -= sum(self.mat_f[k] * xc[k] for k in range(n)) if not self.ldlt_mgr.factorize(A): ep = self.ldlt_mgr.witness() g = np.array([self.ldlt_mgr.sym_quad(self.mat_f[i]) for i in range(n)]) return g, ep return None