Source code for corr_solver.qmi_oracle
# -*- coding: utf-8 -*-
from typing import List, Optional, Tuple, Union
import numpy as np
from .gmi_oracle import GMIOracle
Arr = Union[np.ndarray]
Cut = Tuple[Arr, float]
[docs]
class QMIOracle:
[docs]
class QMI:
"""Oracle for Quadratic Matrix Inequality
The QMI class represents an oracle for solving a quadratic matrix inequality problem.
find x
s.t. t*I - F(x)' F(x) ⪰ 0
where
F(x) = F0 - (F1 * x1 + F2 * x2 + ...)
"""
t = 0.0
count = 0
def __init__(self, F: List[Arr], F0: Arr):
"""
The function initializes the variables F, F0, and Fx with the given arguments.
:param F: F is a list of arrays. Each array in the list represents a feature vector. The
feature vectors can have different lengths, but they all have the same number of columns
:type F: List[Arr]
:param F0: F0 is a 2-dimensional array (matrix) representing the initial state of the
system. It has n rows and m columns
:type F0: Arr
"""
self.F = F
self.F0 = F0
n, m = F0.shape
self.Fx = np.zeros([m, n])
[docs]
def update(self, t: float):
"""
The `update` function updates the value of `self.t` with the input `t`.
:param t: The parameter `t` represents the best-so-far optimal value
:type t: float
"""
self.t = t
[docs]
def eval(self, row, col, x: Arr) -> float:
"""
The `eval` function calculates a value based on the given parameters and returns it.
:param row: The parameter `row` represents the row index of the element in the matrix
:param col: The parameter `col` represents the column index of the element in the matrix
:param x: The parameter `x` is an array
:type x: Arr
:return: a float value.
"""
if row < col:
raise AssertionError()
if self.count < row + 1:
nx = len(x)
self.count = row + 1
self.Fx[row] = self.F0[:, row]
self.Fx[row] -= sum(self.F[k][:, row] * x[k] for k in range(nx))
a = float(-(self.Fx[row] @ self.Fx[col]))
if row == col:
return self.t + a
return a
[docs]
def neg_grad_sym_quad(self, Q, _: Arr):
"""
The function `neg_grad_sym_quad` calculates the negative gradient of a symmetric quadratic function.
:param Q: Q is a quadratic matrix represented as a sparse matrix. It has two attributes: p and v. p
is a tuple representing the starting and ending indices of the non-zero elements in the matrix, and
v is a numpy array representing the values of the non-zero elements
:param _: The parameter `_` is an unused placeholder parameter
:type _: Arr
:return: the gradient vector `g`.
"""
s, n = Q.pos
v = Q.wit[s:n]
Av = v @ self.Fx[s:n]
g = np.array([-2 * ((v @ Fk[s:n]) @ Av) for Fk in self.F])
return g
def __init__(self, F, F0):
"""
The function initializes an object with attributes qmi, gmi, and Q based on the input arguments F
and F0.
:param F: A list of arrays. Each array represents a feature matrix for a different class. The
feature matrix has shape (n, m), where n is the number of samples and m is the number of features
:param F0: F0 is a 2-dimensional array representing the reference distribution. It has n rows and m
columns
"""
_, m = F0.shape
self.qmi = self.QMI(F, F0)
self.gmi = GMIOracle(self.qmi, m)
self.ldlt_mgr = self.gmi.ldlt_mgr
[docs]
def update(self, t: float):
"""
The function updates the best-so-far optimal value.
:param t: The parameter `t` represents the best-so-far optimal value
:type t: float
"""
self.qmi.update(t)
[docs]
def assess_feas(self, x: Arr) -> Optional[Cut]:
"""
The `assess_feas` function assesses the feasibility of a given input and returns a cut if it is
feasible.
:param x: An array of values
:type x: Arr
:return: an Optional[Cut] object.
"""
self.qmi.count = 0
return self.gmi.assess_feas(x)