24#include "vnl/vnl_matrix.h"
25#include "vnl/vnl_matrix_fixed.h"
26#include "vnl/vnl_vector.h"
27#include "vnl/vnl_vector_fixed.h"
30#include ITK_EIGEN(Dense)
42template <
typename TReal>
46 return rcond < TReal{ 0 } ?
static_cast<TReal
>(n) * std::numeric_limits<TReal>::epsilon() : rcond;
51template <
typename TMatrix,
typename TVector,
typename TReal>
53PseudoInverse(
const TMatrix & U,
const TVector & W,
const TMatrix & V, TReal rcond)
55 const unsigned int k = W.size();
59 for (
unsigned int col = 0; col < k; ++col)
61 const TReal s = (W[col] > tol) ? TReal{ 1 } / W[col] : TReal{ 0 };
62 for (
unsigned int i = 0; i < scaledV.rows(); ++i)
67 return scaledV * U.transpose();
71template <
typename TMatrix,
typename TVector,
typename TReal>
73SolveLinear(
const TMatrix & U,
const TVector & W,
const TMatrix & V,
const TVector & b, TReal rcond)
75 const unsigned int n = W.size();
77 TVector utb = U.transpose() * b;
78 for (
unsigned int k = 0; k < n; ++k)
80 utb[k] = (W[k] > tol) ? utb[k] / W[k] : TReal{ 0 };
85template <
typename TVector,
typename TReal>
89 const unsigned int n = W.size();
91 unsigned int count = 0;
92 for (
unsigned int k = 0; k < n; ++k)
104template <
typename TMatrix,
typename TVector,
typename TReal>
106Recompose(
const TMatrix & U,
const TVector & W,
const TMatrix & V, TReal rcond)
108 const unsigned int k = W.size();
111 for (
unsigned int col = 0; col < k; ++col)
113 const TReal s = (W[col] > tol) ? W[col] : TReal{ 0 };
114 for (
unsigned int i = 0; i < scaledU.rows(); ++i)
116 scaledU(i, col) *= s;
119 return scaledU * V.transpose();
125template <
typename TReal,
unsigned int VDim>
128 vnl_matrix_fixed<TReal, VDim, VDim>
U{};
129 vnl_vector_fixed<TReal, VDim>
W{};
130 vnl_matrix_fixed<TReal, VDim, VDim>
V{};
133 vnl_matrix_fixed<TReal, VDim, VDim>
140 vnl_vector_fixed<TReal, VDim>
141 Solve(
const vnl_vector_fixed<TReal, VDim> & b, TReal rcond = TReal{ -1 })
const
148 Rank(TReal rcond = TReal{ -1 })
const
154 vnl_matrix_fixed<TReal, VDim, VDim>
164template <
typename TReal>
167 vnl_matrix<TReal>
U{};
168 vnl_vector<TReal>
W{};
169 vnl_matrix<TReal>
V{};
180 Solve(
const vnl_vector<TReal> & b, TReal rcond = TReal{ -1 })
const
187 Rank(TReal rcond = TReal{ -1 })
const
212template <
typename TReal>
216 using RowMajor = Eigen::Matrix<TReal, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
217 using ColMajor = Eigen::Matrix<TReal, Eigen::Dynamic, Eigen::Dynamic>;
218 constexpr int full = Eigen::ComputeFullU | Eigen::ComputeFullV;
220 const Eigen::Map<const RowMajor> inMap(inData, n, n);
221 Eigen::Map<RowMajor> uMap(uData, n, n);
222 Eigen::Map<RowMajor> vMap(vData, n, n);
224 const auto extract = [&](
const auto & svd) {
225 if (svd.info() != Eigen::Success)
227 itkGenericExceptionMacro(
"itk::Math::SVD failed; input is likely non-finite (NaN/Inf).");
229 uMap = svd.matrixU();
230 vMap = svd.matrixV();
231 for (
unsigned int i = 0; i < n; ++i)
233 wData[i] = svd.singularValues()[i];
239 extract(Eigen::JacobiSVD < ColMajor, full | Eigen::NoQRPreconditioner > (inMap));
243 extract(Eigen::BDCSVD<ColMajor, full>(inMap));
249template <
unsigned int VDim,
typename TReal>
262 using RowMajor = Eigen::Matrix<TReal, VDim, VDim, Eigen::RowMajor>;
263 using ColMajor = Eigen::Matrix<TReal, VDim, VDim>;
264 constexpr int options = Eigen::ComputeFullU | Eigen::ComputeFullV | Eigen::NoQRPreconditioner;
266 const Eigen::Map<const RowMajor> inMap(inData);
267 const Eigen::JacobiSVD<ColMajor, options> svd(inMap);
268 if (svd.info() != Eigen::Success)
270 itkGenericExceptionMacro(
"itk::Math::SVD failed; input is likely non-finite (NaN/Inf).");
273 Eigen::Map<RowMajor> uMap(uData);
274 Eigen::Map<RowMajor> vMap(vData);
275 uMap = svd.matrixU();
276 vMap = svd.matrixV();
277 for (
unsigned int i = 0; i < VDim; ++i)
279 wData[i] = svd.singularValues()[i];
287template <
typename TReal>
296 using RowMajor = Eigen::Matrix<TReal, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
297 using ColMajor = Eigen::Matrix<TReal, Eigen::Dynamic, Eigen::Dynamic>;
298 constexpr int thin = Eigen::ComputeThinU | Eigen::ComputeThinV;
299 const unsigned int k = (rows < cols) ? rows : cols;
301 const Eigen::Map<const RowMajor> inMap(inData, rows, cols);
302 const Eigen::BDCSVD<ColMajor, thin> svd(inMap);
303 if (svd.info() != Eigen::Success)
305 itkGenericExceptionMacro(
"itk::Math::SVD failed; input is likely non-finite (NaN/Inf).");
307 Eigen::Map<RowMajor> uMap(uData, rows, k);
308 Eigen::Map<RowMajor> vMap(vData, cols, k);
309 uMap = svd.matrixU();
310 vMap = svd.matrixV();
311 for (
unsigned int i = 0; i < k; ++i)
313 wData[i] = svd.singularValues()[i];
348template <
typename TReal,
unsigned int VDim>
349FixedSquareSVDResult<TReal, VDim>
350SVD(
const vnl_matrix_fixed<TReal, VDim, VDim> & A,
bool canonicalizeSigns =
true)
354 if (canonicalizeSigns)
362template <
typename TReal,
unsigned int VDim>
363FixedSquareSVDResult<TReal, VDim>
372template <
typename TReal>
374SVD(
const vnl_matrix<TReal> & A,
bool canonicalizeSigns =
true)
376 const unsigned int rows = A.rows();
377 const unsigned int cols = A.cols();
378 if (rows == 0 || cols == 0)
380 itkGenericExceptionMacro(
"itk::Math::SVD requires a non-empty matrix.");
382 const unsigned int k = (rows < cols) ? rows : cols;
384 result.
U.set_size(rows, k);
385 result.
V.set_size(cols, k);
386 result.
W.set_size(k);
390 A.data_block(), rows, result.
U.data_block(), result.
W.data_block(), result.
V.data_block());
395 A.data_block(), rows, cols, result.
U.data_block(), result.
W.data_block(), result.
V.data_block());
397 if (canonicalizeSigns)
A templated class holding a M x N size Matrix.
InternalMatrixType & GetVnlMatrix()
FixedSquareSVDResult< TReal, VDim > SVD(const vnl_matrix_fixed< TReal, VDim, VDim > &A, bool canonicalizeSigns=true)
Singular value decomposition A = U diag(W) V^T, backed by Eigen.
Cholesky-based linear algebra for symmetric matrices, backed by Eigen.
void DynamicSquareSVDEigen(const TReal *inData, unsigned int n, TReal *uData, TReal *wData, TReal *vData)
TMatrix PseudoInverse(const TMatrix &U, const TVector &W, const TMatrix &V, TReal rcond)
void RectangularSVDEigen(const TReal *inData, unsigned int rows, unsigned int cols, TReal *uData, TReal *wData, TReal *vData)
TReal ResolveRcond(TReal rcond, unsigned int n)
TMatrix Recompose(const TMatrix &U, const TVector &W, const TMatrix &V, TReal rcond)
constexpr unsigned int kFixedSVDMaxDim
constexpr unsigned int kJacobiMaxDim
TVector SolveLinear(const TMatrix &U, const TVector &W, const TMatrix &V, const TVector &b, TReal rcond)
void SquareSVDEigen(const TReal *inData, TReal *uData, TReal *wData, TReal *vData)
unsigned int NumericalRank(const TVector &W, TReal rcond)
void CanonicalizeColumnSignsPaired(TMatrix &u, TMatrix &paired)
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
vnl_matrix_fixed< TReal, VDim, VDim > PseudoInverse(TReal rcond=TReal{ -1 }) const
vnl_vector_fixed< TReal, VDim > Solve(const vnl_vector_fixed< TReal, VDim > &b, TReal rcond=TReal{ -1 }) const
vnl_matrix_fixed< TReal, VDim, VDim > Recompose(TReal rcond=TReal{ -1 }) const
vnl_vector_fixed< TReal, VDim > W
vnl_matrix_fixed< TReal, VDim, VDim > U
vnl_matrix_fixed< TReal, VDim, VDim > V
unsigned int Rank(TReal rcond=TReal{ -1 }) const
vnl_matrix< TReal > Recompose(TReal rcond=TReal{ -1 }) const
vnl_matrix< TReal > PseudoInverse(TReal rcond=TReal{ -1 }) const
unsigned int Rank(TReal rcond=TReal{ -1 }) const
vnl_vector< TReal > Solve(const vnl_vector< TReal > &b, TReal rcond=TReal{ -1 }) const