/* Example programs from the book Scientific and Engineering Programming in C++: An Introduction with Advanced Techniques and Examples, Addison-Wesley, 1994. (c) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 1994. ALL RIGHTS RESERVED. See README file for further details. */ #include "SciEng/utils.h" #include "SciEng/NumericalLimits.h" #include "LapackWrap/LapackSubroutines.h" template RectSVDRep::Factored::Factored(RectSVDRep::Unfactored* mp) : facmat_p(mp), m( mp->shape(0) ), n( mp->shape(1) ), k( min(m, n) ), sigma(k), // k X k diagonal matrix, stored as vector u(m, k), // m X k v_T(k, n) { // k X n // Minimum size work area required by LAPACK ConcreteFortranArray1d work( max(3 * k + max(m,n), 5 * k - 4) ); int info; // info return from LAPACK factor routine. LapackSubroutines::xgesvd( LapackSubroutines::separate, // Give just left singular vectors, in u. LapackSubroutines::separate, // Give just right singular vectors, in v_t. m, n, mp->firstDatum(), mp->shape(0), // A sigma.firstDatum(), // sigma's u.firstDatum(), u.shape(0), // U v_T.firstDatum(), v_T.shape(0), // V^T work.firstDatum(), work.numElts(), // Work area info // Return code ); if (info != 0) throw LapackErr::UnableToFactorSVD(info); } #include "LapackWrap/TransposedConcreteBlas2d.h" template void RectSVDRep::Factored::solve(RectSVDRep::Knowns2d& b) { b = TransposedConcreteBlas2d(u) * b; // U^T * b pseudoInvert(b); // sigma~^+ * b b = TransposedConcreteBlas2d(v_T) * b; // V * b } template void RectSVDRep::Factored::pseudoInvert(RectSVDRep::Knowns2d& b) { T tol = zeroingTol(); for (Subscript i = 0; i < k; i++) { if ( sigma(i) < tol ) b.row(i) = T(0); else b.row(i) *= T(1) / sigma(i); } } template T RectSVDRep::Factored::zeroingTol() const { return NumericalLimits::epsilon * n * sigma(0); } template void RectSVDRep::Factored::solve(RectSVDRep::Unknowns2d& x, const RectSVDRep::Knowns2d& b) { TransposedConcreteBlas2d u_T(u); x = u_T * b; pseudoInvert(x); x = TransposedConcreteBlas2d(v_T) * x; } template void RectSVDRep::Factored::solve(RectSVDRep::Knowns1d& b) { b = TransposedConcreteBlas2d(u) * b; pseudoInvert(b); b = TransposedConcreteBlas2d(v_T) * b; } template void RectSVDRep::Factored::solve(RectSVDRep::Unknowns1d& x, const RectSVDRep::Knowns1d& b) { TransposedConcreteBlas2d u_T(u); x = u_T * b; pseudoInvert(x); x = TransposedConcreteBlas2d(v_T) * x; } template void RectSVDRep::Factored::pseudoInvert(RectSVDRep::Knowns1d& b) { T tol = zeroingTol(); for (Subscript i = 0; i < k; i++) { if ( sigma(i) < tol ) b(i) = T(0); else b(i) *= T(1) / sigma(i); } }