Source code for UQpy.dimension_reduction.grassmann_manifold.projections.SVDProjection

from typing import Union

from beartype import beartype

from UQpy.utilities.GrassmannPoint import GrassmannPoint
from UQpy.dimension_reduction.grassmann_manifold.projections.baseclass.GrassmannProjection import GrassmannProjection
from UQpy.utilities.ValidationTypes import Numpy2DFloatArray
from UQpy.utilities.Utilities import *


[docs]class SVDProjection(GrassmannProjection): @beartype def __init__( self, data: list[Numpy2DFloatArray], p: Union[int, str], tol: float = None, ): """ :param data: Raw data given as a list of matrices. :param p: Number of independent p-planes of each Grassmann point. Options: :any:`int`: Integer specifying the number of p-planes :any:`str`: `"max"`: Set p equal to the maximum rank of all provided data matrices `"min"`: Set p equal to the minimum rank of all provided data matrices :param tol: Tolerance on the SVD """ self.data = data self.tolerance = tol points_number = len(data) n_left = [] n_right = [] for i in range(points_number): n_left.append(max(np.shape(data[i]))) n_right.append(min(np.shape(data[i]))) bool_left = n_left.count(n_left[0]) != len(n_left) bool_right = n_right.count(n_right[0]) != len(n_right) if bool_left and bool_right: raise TypeError("UQpy: The shape of the input matrices must be the same.") n_u = n_left[0] n_v = n_right[0] ranks = [np.linalg.matrix_rank(data[i], tol=self.tolerance) for i in range(points_number)] if isinstance(p, str) and p == "min": p = int(min(ranks)) elif isinstance(p, str) and p == "max": p = int(max(ranks)) elif isinstance(p, str): raise ValueError("The input parameter p must me either 'min', 'max' or a integer.") else: for i in range(points_number): if min(np.shape(data[i])) < p: raise ValueError("UQpy: The dimension of the input data is not consistent with `p` of G(n,p).") # write something that makes sense ranks = np.ones(points_number) * [int(p)] ranks = ranks.tolist() ranks = list(map(int, ranks)) phi = [] # initialize the left singular eigenvectors as a list. sigma = [] # initialize the singular values as a list. psi = [] # initialize the right singular eigenvectors as a list. for i in range(points_number): u, s, v = svd(data[i], int(ranks[i])) phi.append(GrassmannPoint(u)) sigma.append(np.diag(s)) psi.append(GrassmannPoint(v)) self.input_points = data self.u: list[GrassmannPoint] = phi """Left singular vectors from the SVD of each sample in `data` representing a point on the Grassmann manifold. """ self.sigma: np.ndarray = sigma """Singular values from the SVD of each sample in `data`.""" self.v: list[GrassmannPoint] = psi """Right singular vectors from the SVD of each sample in `data` representing a point on the Grassmann manifold.""" self.n_u = n_u self.n_v = n_v self.p = p self.ranks = ranks self.points_number = points_number self.max_rank = int(np.max(ranks))