Working on an SVD implimentation
This commit is contained in:
+131
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
#include "Matrix.hpp"
|
||||
|
||||
/**
|
||||
* @brief library that uses Matrix.hpp and performs SVD on a matrix
|
||||
*/
|
||||
namespace SVD {
|
||||
/**
|
||||
* @brief Compute the Singular Value Decomposition (SVD) of this matrix.
|
||||
*
|
||||
* Decomposes A into U × Σ × Vᵀ where:
|
||||
* - U is an m×k orthogonal matrix (left singular vectors)
|
||||
* - Σ is a k×k diagonal matrix with non-negative singular values
|
||||
* (stored as a k×1 column vector)
|
||||
* - Vᵀ is a k×n orthogonal matrix (right singular vectors, transposed)
|
||||
* - k = min(m, n)
|
||||
*
|
||||
* The decomposition satisfies: A ≈ U × diag(Σ) × Vᵀ
|
||||
* Singular values are returned in descending order.
|
||||
*
|
||||
* @param U Output: left singular vectors (m×k orthogonal matrix)
|
||||
* @param sigma Output: singular values as k×1 column vector, sorted descending
|
||||
* @param Vt Output: right singular vectors transposed (k×n matrix)
|
||||
*
|
||||
* @note This implementation uses the Golub-Kahan-Reinsch algorithm:
|
||||
* 1. Householder bidiagonalization of A
|
||||
* 2. Implicit QR iteration on the bidiagonal matrix
|
||||
* 3. Accumulation of U and V factors throughout
|
||||
*/
|
||||
template <uint8_t rows, uint8_t columns>
|
||||
void SVD(Matrix<rows, columns> &matrixToDecompose, Matrix<rows, columns> &U,
|
||||
Matrix<columns, 1> &sigma, Matrix<columns, columns> &Vt);
|
||||
|
||||
// ========================================================================
|
||||
// SVD Building Block Functions (for unit testing)
|
||||
// These operate on internal 5×5 working arrays for maximum flexibility.
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Compute a Householder reflector vector.
|
||||
*
|
||||
* Given input vector x, computes normalized v and scalar alpha such that:
|
||||
* (I - 2·v·vᵀ) · x = [alpha, 0, 0, ...]ᵀ
|
||||
*
|
||||
* @param x Input vector (up to 5 elements)
|
||||
* @param len Number of valid elements in x
|
||||
* @param v Output: normalized Householder vector (v[0] is the first element)
|
||||
* @param alpha Output: the resulting first element after reflection
|
||||
* @return The norm of the input vector x
|
||||
*/
|
||||
static float ComputeHouseholder(const float *x, uint8_t len, float *v,
|
||||
float &alpha);
|
||||
|
||||
/**
|
||||
* @brief Apply a Householder reflection from the left.
|
||||
*
|
||||
* Transforms W = (I - 2·v·vᵀ) · W where v operates on rows [startRow..endRow].
|
||||
*
|
||||
* @param W Input/output: matrix to transform (5×5 working array)
|
||||
* @param v Householder vector (length = endRow - startRow + 1)
|
||||
* @param startRow First row index
|
||||
* @param endRow Last row index
|
||||
*/
|
||||
static void ApplyHouseholderLeft(Matrix<5, 5> &W, const float *v,
|
||||
uint8_t startRow, uint8_t endRow);
|
||||
|
||||
/**
|
||||
* @brief Apply a Householder reflection from the right.
|
||||
*
|
||||
* Transforms W = W · (I - 2·v·vᵀ) where v operates on columns
|
||||
* [startCol..endCol].
|
||||
*
|
||||
* @param W Input/output: matrix to transform (5×5 working array)
|
||||
* @param v Householder vector (length = endCol - startCol + 1)
|
||||
* @param startCol First column index
|
||||
* @param endCol Last column index
|
||||
*/
|
||||
static void ApplyHouseholderRight(Matrix<5, 5> &W, const float *v,
|
||||
uint8_t startCol, uint8_t endCol);
|
||||
|
||||
/**
|
||||
* @brief Compute a Givens rotation that zeros out y.
|
||||
*
|
||||
* Computes c, s such that:
|
||||
* [c s] [x] = [r]
|
||||
* [-s c] [y] [0]
|
||||
* where r = sqrt(x² + y²).
|
||||
*
|
||||
* @param x First element
|
||||
* @param y Second element (to be zeroed)
|
||||
* @param c Output: cosine of rotation angle
|
||||
* @param s Output: sine of rotation angle
|
||||
*/
|
||||
static void ComputeGivens(float x, float y, float &c, float &s);
|
||||
|
||||
/**
|
||||
* @brief Apply a Givens rotation from the left to rows i and j.
|
||||
*
|
||||
* Applies [c s; -s c] to rows i, j of W (columns startCol..endCol).
|
||||
*
|
||||
* @param W Input/output: matrix to transform
|
||||
* @param i First row index
|
||||
* @param j Second row index
|
||||
* @param c Cosine of rotation angle
|
||||
* @param s Sine of rotation angle
|
||||
* @param startCol First column to transform
|
||||
* @param endCol Last column to transform
|
||||
*/
|
||||
static void ApplyGivensLeft(Matrix<5, 5> &W, uint8_t i, uint8_t j, float c,
|
||||
float s, uint8_t startCol, uint8_t endCol);
|
||||
|
||||
/**
|
||||
* @brief Apply a Givens rotation from the right to columns i and j.
|
||||
*
|
||||
* Applies [c -s; s c]ᵀ to columns i, j of W (rows startRow..endRow).
|
||||
*
|
||||
* @param W Input/output: matrix to transform
|
||||
* @param i First column index
|
||||
* @param j Second column index
|
||||
* @param c Cosine of rotation angle
|
||||
* @param s Sine of rotation angle
|
||||
* @param startRow First row to transform
|
||||
* @param endRow Last row to transform
|
||||
*/
|
||||
static void ApplyGivensRight(Matrix<5, 5> &W, uint8_t i, uint8_t j, float c,
|
||||
float s, uint8_t startRow, uint8_t endRow);
|
||||
} // namespace SVD
|
||||
|
||||
#ifndef SVD_H_
|
||||
#include "SVD.cpp"
|
||||
#endif // SVD_H_
|
||||
Reference in New Issue
Block a user