20 #ifndef EIGEN_BDCSVD_H
21 #define EIGEN_BDCSVD_H
25 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
26 #undef eigen_internal_assert
27 #define eigen_internal_assert(X) assert(X);
32 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
33 IOFormat bdcsvdfmt(8, 0,
", ",
"\n",
" [",
"]");
36 template<
typename _MatrixType>
class BDCSVD;
40 template<
typename _MatrixType>
44 typedef _MatrixType MatrixType;
72 template<
typename _MatrixType>
83 typedef _MatrixType MatrixType;
84 typedef typename MatrixType::Scalar Scalar;
88 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
89 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
90 DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime),
91 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
92 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
93 MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime, MaxColsAtCompileTime),
94 MatrixOptions = MatrixType::Options
114 BDCSVD() : m_algoswap(16), m_isTranspose(false), m_compU(false), m_compV(false), m_numIters(0)
125 : m_algoswap(16), m_numIters(0)
127 allocate(rows, cols, computationOptions);
140 BDCSVD(
const MatrixType& matrix,
unsigned int computationOptions = 0)
141 : m_algoswap(16), m_numIters(0)
143 compute(matrix, computationOptions);
160 BDCSVD&
compute(
const MatrixType& matrix,
unsigned int computationOptions);
170 return compute(matrix, this->m_computationOptions);
173 void setSwitchSize(
int s)
175 eigen_assert(s>3 &&
"BDCSVD the size of the algo switch has to be greater than 3");
180 void allocate(
Index rows,
Index cols,
unsigned int computationOptions);
182 void computeSVDofM(
Index firstCol,
Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V);
183 void computeSingVals(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm, VectorType& singVals, ArrayRef shifts, ArrayRef mus);
184 void perturbCol0(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm,
const VectorType& singVals,
const ArrayRef& shifts,
const ArrayRef& mus, ArrayRef zhat);
185 void computeSingVecs(
const ArrayRef& zhat,
const ArrayRef& diag,
const IndicesRef& perm,
const VectorType& singVals,
const ArrayRef& shifts,
const ArrayRef& mus, MatrixXr& U, MatrixXr& V);
189 template<
typename HouseholderU,
typename HouseholderV,
typename NaiveU,
typename NaiveV>
190 void copyUV(
const HouseholderU &householderU,
const HouseholderV &householderV,
const NaiveU &naiveU,
const NaiveV &naivev);
191 void structured_update(Block<MatrixXr,Dynamic,Dynamic> A,
const MatrixXr &B,
Index n1);
192 static RealScalar secularEq(RealScalar x,
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef &perm,
const ArrayRef& diagShifted, RealScalar shift);
195 MatrixXr m_naiveU, m_naiveV;
199 ArrayXi m_workspaceI;
201 bool m_isTranspose, m_compU, m_compV;
203 using Base::m_singularValues;
204 using Base::m_diagSize;
205 using Base::m_computeFullU;
206 using Base::m_computeFullV;
207 using Base::m_computeThinU;
208 using Base::m_computeThinV;
209 using Base::m_matrixU;
210 using Base::m_matrixV;
211 using Base::m_isInitialized;
212 using Base::m_nonzeroSingularValues;
220 template<
typename MatrixType>
223 m_isTranspose = (cols > rows);
225 if (Base::allocate(rows, cols, computationOptions))
228 m_computed = MatrixXr::Zero(m_diagSize + 1, m_diagSize );
229 m_compU = computeV();
230 m_compV = computeU();
232 std::swap(m_compU, m_compV);
234 if (m_compU) m_naiveU = MatrixXr::Zero(m_diagSize + 1, m_diagSize + 1 );
235 else m_naiveU = MatrixXr::Zero(2, m_diagSize + 1 );
237 if (m_compV) m_naiveV = MatrixXr::Zero(m_diagSize, m_diagSize);
239 m_workspace.resize((m_diagSize+1)*(m_diagSize+1)*3);
240 m_workspaceI.resize(3*m_diagSize);
243 template<
typename MatrixType>
246 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
247 std::cout <<
"\n\n\n======================================================================================================================\n\n\n";
249 allocate(matrix.rows(), matrix.cols(), computationOptions);
252 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
255 if(matrix.cols() < m_algoswap)
259 if(computeU()) m_matrixU = jsvd.matrixU();
260 if(computeV()) m_matrixV = jsvd.matrixV();
261 m_singularValues = jsvd.singularValues();
262 m_nonzeroSingularValues = jsvd.nonzeroSingularValues();
263 m_isInitialized =
true;
268 RealScalar scale = matrix.cwiseAbs().maxCoeff();
269 if(scale==Literal(0)) scale = Literal(1);
271 if (m_isTranspose) copy = matrix.adjoint()/scale;
272 else copy = matrix/scale;
282 m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose();
283 m_computed.template bottomRows<1>().setZero();
284 divide(0, m_diagSize - 1, 0, 0, 0);
287 for (
int i=0; i<m_diagSize; i++)
289 RealScalar a = abs(m_computed.coeff(i, i));
290 m_singularValues.coeffRef(i) = a * scale;
293 m_nonzeroSingularValues = i;
294 m_singularValues.tail(m_diagSize - i - 1).setZero();
297 else if (i == m_diagSize - 1)
299 m_nonzeroSingularValues = i + 1;
304 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
308 if(m_isTranspose) copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU);
309 else copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV);
311 m_isInitialized =
true;
316 template<
typename MatrixType>
317 template<
typename HouseholderU,
typename HouseholderV,
typename NaiveU,
typename NaiveV>
318 void BDCSVD<MatrixType>::copyUV(
const HouseholderU &householderU,
const HouseholderV &householderV,
const NaiveU &naiveU,
const NaiveV &naiveV)
323 Index Ucols = m_computeThinU ? m_diagSize : householderU.cols();
324 m_matrixU = MatrixX::Identity(householderU.cols(), Ucols);
325 m_matrixU.topLeftCorner(m_diagSize, m_diagSize) = naiveV.template cast<Scalar>().topLeftCorner(m_diagSize, m_diagSize);
326 householderU.applyThisOnTheLeft(m_matrixU);
330 Index Vcols = m_computeThinV ? m_diagSize : householderV.cols();
331 m_matrixV = MatrixX::Identity(householderV.cols(), Vcols);
332 m_matrixV.topLeftCorner(m_diagSize, m_diagSize) = naiveU.template cast<Scalar>().topLeftCorner(m_diagSize, m_diagSize);
333 householderV.applyThisOnTheLeft(m_matrixV);
345 template<
typename MatrixType>
346 void BDCSVD<MatrixType>::structured_update(Block<MatrixXr,Dynamic,Dynamic> A,
const MatrixXr &B,
Index n1)
354 Map<MatrixXr> A1(m_workspace.data() , n1, n);
355 Map<MatrixXr> A2(m_workspace.data()+ n1*n, n2, n);
356 Map<MatrixXr> B1(m_workspace.data()+ n*n, n, n);
357 Map<MatrixXr> B2(m_workspace.data()+2*n*n, n, n);
359 for(
Index j=0; j<n; ++j)
361 if( (A.col(j).head(n1).array()!=Literal(0)).any() )
363 A1.col(k1) = A.col(j).head(n1);
364 B1.row(k1) = B.row(j);
367 if( (A.col(j).tail(n2).array()!=Literal(0)).any() )
369 A2.col(k2) = A.col(j).tail(n2);
370 B2.row(k2) = B.row(j);
375 A.topRows(n1).noalias() = A1.leftCols(k1) * B1.topRows(k1);
376 A.bottomRows(n2).noalias() = A2.leftCols(k2) * B2.topRows(k2);
380 Map<MatrixXr,Aligned> tmp(m_workspace.data(),n,n);
396 template<
typename MatrixType>
403 const Index n = lastCol - firstCol + 1;
405 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
409 RealScalar lambda, phi, c0, s0;
418 m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = b.matrixU();
421 m_naiveU.row(0).segment(firstCol, n + 1).real() = b.matrixU().row(0);
422 m_naiveU.row(1).segment(firstCol, n + 1).real() = b.matrixU().row(n);
424 if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = b.matrixV();
425 m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero();
426 m_computed.diagonal().segment(firstCol + shift, n) = b.singularValues().head(n);
430 alphaK = m_computed(firstCol + k, firstCol + k);
431 betaK = m_computed(firstCol + k + 1, firstCol + k);
435 divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift);
436 divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1);
440 lambda = m_naiveU(firstCol + k, firstCol + k);
441 phi = m_naiveU(firstCol + k + 1, lastCol + 1);
445 lambda = m_naiveU(1, firstCol + k);
446 phi = m_naiveU(0, lastCol + 1);
448 r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) + abs(betaK * phi) * abs(betaK * phi));
451 l = m_naiveU.row(firstCol + k).segment(firstCol, k);
452 f = m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1);
456 l = m_naiveU.row(1).segment(firstCol, k);
457 f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1);
459 if (m_compV) m_naiveV(firstRowW+k, firstColW) = Literal(1);
467 c0 = alphaK * lambda / r0;
468 s0 = betaK * phi / r0;
471 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
472 assert(m_naiveU.allFinite());
473 assert(m_naiveV.allFinite());
474 assert(m_computed.allFinite());
479 MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1));
481 for (
Index i = firstCol + k - 1; i >= firstCol; i--)
482 m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1);
484 m_naiveU.col(firstCol).segment( firstCol, k + 1) = (q1 * c0);
486 m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * ( - s0));
488 m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) = m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0;
490 m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0;
494 RealScalar q1 = m_naiveU(0, firstCol + k);
496 for (
Index i = firstCol + k - 1; i >= firstCol; i--)
497 m_naiveU(0, i + 1) = m_naiveU(0, i);
499 m_naiveU(0, firstCol) = (q1 * c0);
501 m_naiveU(0, lastCol + 1) = (q1 * ( - s0));
503 m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) *s0;
505 m_naiveU(1, lastCol + 1) *= c0;
506 m_naiveU.row(1).segment(firstCol + 1, k).setZero();
507 m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero();
510 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
511 assert(m_naiveU.allFinite());
512 assert(m_naiveV.allFinite());
513 assert(m_computed.allFinite());
516 m_computed(firstCol + shift, firstCol + shift) = r0;
517 m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real();
518 m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real();
520 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
521 ArrayXr tmp1 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues();
524 deflation(firstCol, lastCol, k, firstRowW, firstColW, shift);
525 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
526 ArrayXr tmp2 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues();
527 std::cout <<
"\n\nj1 = " << tmp1.transpose().format(bdcsvdfmt) <<
"\n";
528 std::cout <<
"j2 = " << tmp2.transpose().format(bdcsvdfmt) <<
"\n\n";
529 std::cout <<
"err: " << ((tmp1-tmp2).abs()>1e-12*tmp2.abs()).transpose() <<
"\n";
530 static int count = 0;
531 std::cout <<
"# " << ++count <<
"\n\n";
532 assert((tmp1-tmp2).matrix().norm() < 1e-14*tmp2.matrix().norm());
538 MatrixXr UofSVD, VofSVD;
540 computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD);
542 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
543 assert(UofSVD.allFinite());
544 assert(VofSVD.allFinite());
548 structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2);
551 Map<Matrix<RealScalar,2,Dynamic>,
Aligned> tmp(m_workspace.data(),2,n+1);
552 tmp.noalias() = m_naiveU.middleCols(firstCol, n+1) * UofSVD;
553 m_naiveU.middleCols(firstCol, n + 1) = tmp;
556 if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n+1)/2);
558 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
559 assert(m_naiveU.allFinite());
560 assert(m_naiveV.allFinite());
561 assert(m_computed.allFinite());
564 m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero();
565 m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals;
576 template <
typename MatrixType>
577 void BDCSVD<MatrixType>::computeSVDofM(
Eigen::Index firstCol,
Eigen::Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V)
579 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
581 ArrayRef col0 = m_computed.col(firstCol).segment(firstCol, n);
582 m_workspace.head(n) = m_computed.block(firstCol, firstCol, n, n).diagonal();
583 ArrayRef diag = m_workspace.head(n);
584 diag(0) = Literal(0);
589 if (m_compV) V.resize(n, n);
591 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
592 if (col0.hasNaN() || diag.hasNaN())
593 std::cout <<
"\n\nHAS NAN\n\n";
600 while(actual_n>1 && diag(actual_n-1)==Literal(0)) {--actual_n; eigen_internal_assert(col0(actual_n)==Literal(0)); }
602 for(
Index k=0;k<actual_n;++k)
603 if(abs(col0(k))>considerZero)
604 m_workspaceI(m++) = k;
605 Map<ArrayXi> perm(m_workspaceI.data(),m);
607 Map<ArrayXr> shifts(m_workspace.data()+1*n, n);
608 Map<ArrayXr> mus(m_workspace.data()+2*n, n);
609 Map<ArrayXr> zhat(m_workspace.data()+3*n, n);
611 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
612 std::cout <<
"computeSVDofM using:\n";
613 std::cout <<
" z: " << col0.transpose() <<
"\n";
614 std::cout <<
" d: " << diag.transpose() <<
"\n";
618 computeSingVals(col0, diag, perm, singVals, shifts, mus);
620 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
621 std::cout <<
" j: " << (m_computed.block(firstCol, firstCol, n, n)).jacobiSvd().singularValues().transpose().reverse() <<
"\n\n";
622 std::cout <<
" sing-val: " << singVals.transpose() <<
"\n";
623 std::cout <<
" mu: " << mus.transpose() <<
"\n";
624 std::cout <<
" shift: " << shifts.transpose() <<
"\n";
627 std::cout <<
"\n\n mus: " << mus.head(actual_n).transpose() <<
"\n\n";
628 std::cout <<
" check1 (expect0) : " << ((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n).transpose() <<
"\n\n";
629 assert((((singVals.array()-(shifts+mus)) / singVals.array()).head(actual_n) >= 0).all());
630 std::cout <<
" check2 (>0) : " << ((singVals.array()-diag) / singVals.array()).head(actual_n).transpose() <<
"\n\n";
631 assert((((singVals.array()-diag) / singVals.array()).head(actual_n) >= 0).all());
635 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
636 assert(singVals.allFinite());
637 assert(mus.allFinite());
638 assert(shifts.allFinite());
642 perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat);
643 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
644 std::cout <<
" zhat: " << zhat.transpose() <<
"\n";
647 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
648 assert(zhat.allFinite());
651 computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V);
653 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
654 std::cout <<
"U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() <<
"\n";
655 std::cout <<
"V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() <<
"\n";
658 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
659 assert(m_naiveU.allFinite());
660 assert(m_naiveV.allFinite());
661 assert(m_computed.allFinite());
662 assert(U.allFinite());
663 assert(V.allFinite());
670 for(
Index i=0; i<actual_n-1; ++i)
672 if(singVals(i)>singVals(i+1))
675 swap(singVals(i),singVals(i+1));
676 U.col(i).swap(U.col(i+1));
677 if(m_compV) V.col(i).swap(V.col(i+1));
681 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
683 bool singular_values_sorted = (((singVals.segment(1,actual_n-1)-singVals.head(actual_n-1))).array() >= 0).all();
684 if(!singular_values_sorted)
685 std::cout <<
"Singular values are not sorted: " << singVals.segment(1,actual_n).transpose() <<
"\n";
686 assert(singular_values_sorted);
692 singVals.head(actual_n).reverseInPlace();
693 U.leftCols(actual_n).rowwise().reverseInPlace();
694 if (m_compV) V.leftCols(actual_n).rowwise().reverseInPlace();
696 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
697 JacobiSVD<MatrixXr> jsvd(m_computed.block(firstCol, firstCol, n, n) );
698 std::cout <<
" * j: " << jsvd.singularValues().transpose() <<
"\n\n";
699 std::cout <<
" * sing-val: " << singVals.transpose() <<
"\n";
704 template <
typename MatrixType>
705 typename BDCSVD<MatrixType>::RealScalar BDCSVD<MatrixType>::secularEq(RealScalar mu,
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef &perm,
const ArrayRef& diagShifted, RealScalar shift)
707 Index m = perm.size();
708 RealScalar res = Literal(1);
709 for(
Index i=0; i<m; ++i)
714 res += (col0(j) / (diagShifted(j) - mu)) * (col0(j) / (diag(j) + shift + mu));
720 template <
typename MatrixType>
721 void BDCSVD<MatrixType>::computeSingVals(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef &perm,
722 VectorType& singVals, ArrayRef shifts, ArrayRef mus)
728 Index n = col0.size();
732 while(actual_n>1 && col0(actual_n-1)==Literal(0)) --actual_n;
734 for (
Index k = 0; k < n; ++k)
736 if (col0(k) == Literal(0) || actual_n==1)
740 singVals(k) = k==0 ? col0(0) : diag(k);
742 shifts(k) = k==0 ? col0(0) : diag(k);
747 RealScalar left = diag(k);
750 right = (diag(actual_n-1) + col0.matrix().norm());
757 while(col0(l)==Literal(0)) { ++l; eigen_internal_assert(l<actual_n); }
762 RealScalar mid = left + (right-left) / Literal(2);
763 RealScalar fMid = secularEq(mid, col0, diag, perm, diag, Literal(0));
764 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
765 std::cout <<
"right-left = " << right-left <<
"\n";
768 std::cout <<
" = " << secularEq(left+RealScalar(0.000001)*(right-left), col0, diag, perm, diag, 0)
769 <<
" " << secularEq(left+RealScalar(0.1) *(right-left), col0, diag, perm, diag, 0)
770 <<
" " << secularEq(left+RealScalar(0.2) *(right-left), col0, diag, perm, diag, 0)
771 <<
" " << secularEq(left+RealScalar(0.3) *(right-left), col0, diag, perm, diag, 0)
772 <<
" " << secularEq(left+RealScalar(0.4) *(right-left), col0, diag, perm, diag, 0)
773 <<
" " << secularEq(left+RealScalar(0.49) *(right-left), col0, diag, perm, diag, 0)
774 <<
" " << secularEq(left+RealScalar(0.5) *(right-left), col0, diag, perm, diag, 0)
775 <<
" " << secularEq(left+RealScalar(0.51) *(right-left), col0, diag, perm, diag, 0)
776 <<
" " << secularEq(left+RealScalar(0.6) *(right-left), col0, diag, perm, diag, 0)
777 <<
" " << secularEq(left+RealScalar(0.7) *(right-left), col0, diag, perm, diag, 0)
778 <<
" " << secularEq(left+RealScalar(0.8) *(right-left), col0, diag, perm, diag, 0)
779 <<
" " << secularEq(left+RealScalar(0.9) *(right-left), col0, diag, perm, diag, 0)
780 <<
" " << secularEq(left+RealScalar(0.999999)*(right-left), col0, diag, perm, diag, 0) <<
"\n";
782 RealScalar shift = (k == actual_n-1 || fMid > Literal(0)) ? left : right;
785 Map<ArrayXr> diagShifted(m_workspace.data()+4*n, n);
786 diagShifted = diag - shift;
791 RealScalar midShifted = (right - left) / RealScalar(2);
793 midShifted = -midShifted;
794 RealScalar fMidShifted = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
798 shift = fMidShifted > Literal(0) ? left : right;
799 diagShifted = diag - shift;
804 RealScalar muPrev, muCur;
807 muPrev = (right - left) * RealScalar(0.1);
808 if (k == actual_n-1) muCur = right - left;
809 else muCur = (right - left) * RealScalar(0.5);
813 muPrev = -(right - left) * RealScalar(0.1);
814 muCur = -(right - left) * RealScalar(0.5);
817 RealScalar fPrev = secularEq(muPrev, col0, diag, perm, diagShifted, shift);
818 RealScalar fCur = secularEq(muCur, col0, diag, perm, diagShifted, shift);
819 if (abs(fPrev) < abs(fCur))
827 bool useBisection = fPrev*fCur>Literal(0);
828 while (fCur!=Literal(0) && abs(muCur - muPrev) > Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(muCur), abs(muPrev)) && abs(fCur - fPrev)>NumTraits<RealScalar>::epsilon() && !useBisection)
833 RealScalar a = (fCur - fPrev) / (Literal(1)/muCur - Literal(1)/muPrev);
834 RealScalar b = fCur - a / muCur;
836 RealScalar muZero = -a/b;
837 RealScalar fZero = secularEq(muZero, col0, diag, perm, diagShifted, shift);
839 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
840 assert((numext::isfinite)(fZero));
848 if (shift == left && (muCur < Literal(0) || muCur > right - left)) useBisection =
true;
849 if (shift == right && (muCur < -(right - left) || muCur > Literal(0))) useBisection =
true;
850 if (abs(fCur)>abs(fPrev)) useBisection =
true;
856 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
857 std::cout <<
"useBisection for k = " << k <<
", actual_n = " << actual_n <<
"\n";
859 RealScalar leftShifted, rightShifted;
864 leftShifted = numext::maxi<RealScalar>( (std::numeric_limits<RealScalar>::min)(), Literal(2) * abs(col0(k)) / sqrt((std::numeric_limits<RealScalar>::max)()) );
867 eigen_internal_assert( (numext::isfinite)( (col0(k)/leftShifted)*(col0(k)/(diag(k)+shift+leftShifted)) ) );
870 rightShifted = (k==actual_n-1) ? right : ((right - left) * RealScalar(0.51));
874 leftShifted = -(right - left) * RealScalar(0.51);
876 rightShifted = -numext::maxi<RealScalar>( (std::numeric_limits<RealScalar>::min)(), abs(col0(k+1)) / sqrt((std::numeric_limits<RealScalar>::max)()) );
878 rightShifted = -(std::numeric_limits<RealScalar>::min)();
881 RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift);
882 eigen_internal_assert(fLeft<Literal(0));
884 #if defined EIGEN_INTERNAL_DEBUGGING || defined EIGEN_BDCSVD_SANITY_CHECKS
885 RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift);
888 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
889 if(!(numext::isfinite)(fLeft))
890 std::cout <<
"f(" << leftShifted <<
") =" << fLeft <<
" ; " << left <<
" " << shift <<
" " << right <<
"\n";
891 assert((numext::isfinite)(fLeft));
893 if(!(numext::isfinite)(fRight))
894 std::cout <<
"f(" << rightShifted <<
") =" << fRight <<
" ; " << left <<
" " << shift <<
" " << right <<
"\n";
898 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
899 if(!(fLeft * fRight<0))
901 std::cout <<
"f(leftShifted) using leftShifted=" << leftShifted <<
" ; diagShifted(1:10):" << diagShifted.head(10).transpose() <<
"\n ; "
902 <<
"left==shift=" << bool(left==shift) <<
" ; left-shift = " << (left-shift) <<
"\n";
903 std::cout <<
"k=" << k <<
", " << fLeft <<
" * " << fRight <<
" == " << fLeft * fRight <<
" ; "
904 <<
"[" << left <<
" .. " << right <<
"] -> [" << leftShifted <<
" " << rightShifted <<
"], shift=" << shift
905 <<
" , f(right)=" << secularEq(0, col0, diag, perm, diagShifted, shift)
906 <<
" == " << secularEq(right, col0, diag, perm, diag, 0) <<
" == " << fRight <<
"\n";
909 eigen_internal_assert(fLeft * fRight < Literal(0));
913 while (rightShifted - leftShifted > Literal(2) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted)))
915 RealScalar midShifted = (leftShifted + rightShifted) / Literal(2);
916 fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
917 eigen_internal_assert((numext::isfinite)(fMid));
919 if (fLeft * fMid < Literal(0))
921 rightShifted = midShifted;
925 leftShifted = midShifted;
929 muCur = (leftShifted + rightShifted) / Literal(2);
937 muCur = (right - left) * RealScalar(0.5);
943 singVals[k] = shift + muCur;
947 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
949 std::cout <<
"found " << singVals[k] <<
" == " << shift <<
" + " << muCur <<
" from " << diag(k) <<
" .. " << diag(k+1) <<
"\n";
951 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
952 assert(k==0 || singVals[k]>=singVals[k-1]);
953 assert(singVals[k]>=diag(k));
966 template <
typename MatrixType>
967 void BDCSVD<MatrixType>::perturbCol0
968 (
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef &perm,
const VectorType& singVals,
969 const ArrayRef& shifts,
const ArrayRef& mus, ArrayRef zhat)
972 Index n = col0.size();
973 Index m = perm.size();
979 Index lastIdx = perm(m-1);
981 for (
Index k = 0; k < n; ++k)
983 if (col0(k) == Literal(0))
984 zhat(k) = Literal(0);
988 RealScalar dk = diag(k);
989 RealScalar prod = (singVals(lastIdx) + dk) * (mus(lastIdx) + (shifts(lastIdx) - dk));
990 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
992 std::cout <<
"k = " << k <<
" ; z(k)=" << col0(k) <<
", diag(k)=" << dk <<
"\n";
993 std::cout <<
"prod = " <<
"(" << singVals(lastIdx) <<
" + " << dk <<
") * (" << mus(lastIdx) <<
" + (" << shifts(lastIdx) <<
" - " << dk <<
"))" <<
"\n";
994 std::cout <<
" = " << singVals(lastIdx) + dk <<
" * " << mus(lastIdx) + (shifts(lastIdx) - dk) <<
"\n";
999 for(
Index l = 0; l<m; ++l)
1004 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1005 if(i>=k && (l==0 || l-1>=m))
1007 std::cout <<
"Error in perturbCol0\n";
1008 std::cout <<
" " << k <<
"/" << n <<
" " << l <<
"/" << m <<
" " << i <<
"/" << n <<
" ; " << col0(k) <<
" " << diag(k) <<
" " <<
"\n";
1009 std::cout <<
" " <<diag(i) <<
"\n";
1010 Index j = (i<k ) ? i : perm(l-1);
1011 std::cout <<
" " <<
"j=" << j <<
"\n";
1014 Index j = i<k ? i : perm(l-1);
1015 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1016 if(!(dk!=Literal(0) || diag(i)!=Literal(0)))
1018 std::cout <<
"k=" << k <<
", i=" << i <<
", l=" << l <<
", perm.size()=" << perm.size() <<
"\n";
1020 assert(dk!=Literal(0) || diag(i)!=Literal(0));
1022 prod *= ((singVals(j)+dk) / ((diag(i)+dk))) * ((mus(j)+(shifts(j)-dk)) / ((diag(i)-dk)));
1023 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1026 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1027 if(i!=k && numext::abs(((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) - 1) > 0.9 )
1028 std::cout <<
" " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) <<
" == (" << (singVals(j)+dk) <<
" * " << (mus(j)+(shifts(j)-dk))
1029 <<
") / (" << (diag(i)+dk) <<
" * " << (diag(i)-dk) <<
")\n";
1033 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1034 std::cout <<
"zhat(" << k <<
") = sqrt( " << prod <<
") ; " << (singVals(lastIdx) + dk) <<
" * " << mus(lastIdx) + shifts(lastIdx) <<
" - " << dk <<
"\n";
1036 RealScalar tmp = sqrt(prod);
1037 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1038 assert((numext::isfinite)(tmp));
1040 zhat(k) = col0(k) > Literal(0) ? RealScalar(tmp) : RealScalar(-tmp);
1046 template <
typename MatrixType>
1047 void BDCSVD<MatrixType>::computeSingVecs
1048 (
const ArrayRef& zhat,
const ArrayRef& diag,
const IndicesRef &perm,
const VectorType& singVals,
1049 const ArrayRef& shifts,
const ArrayRef& mus, MatrixXr& U, MatrixXr& V)
1051 Index n = zhat.size();
1052 Index m = perm.size();
1054 for (
Index k = 0; k < n; ++k)
1056 if (zhat(k) == Literal(0))
1058 U.col(k) = VectorType::Unit(n+1, k);
1059 if (m_compV) V.col(k) = VectorType::Unit(n, k);
1064 for(
Index l=0;l<m;++l)
1067 U(i,k) = zhat(i)/(((diag(i) - shifts(k)) - mus(k)) )/( (diag(i) + singVals[k]));
1069 U(n,k) = Literal(0);
1070 U.col(k).normalize();
1075 for(
Index l=1;l<m;++l)
1078 V(i,k) = diag(i) * zhat(i) / (((diag(i) - shifts(k)) - mus(k)) )/( (diag(i) + singVals[k]));
1080 V(0,k) = Literal(-1);
1081 V.col(k).normalize();
1085 U.col(n) = VectorType::Unit(n+1, n);
1092 template <
typename MatrixType>
1098 Index start = firstCol + shift;
1099 RealScalar c = m_computed(start, start);
1100 RealScalar s = m_computed(start+i, start);
1101 RealScalar r = numext::hypot(c,s);
1102 if (r == Literal(0))
1104 m_computed(start+i, start+i) = Literal(0);
1107 m_computed(start,start) = r;
1108 m_computed(start+i, start) = Literal(0);
1109 m_computed(start+i, start+i) = Literal(0);
1111 JacobiRotation<RealScalar> J(c/r,-s/r);
1112 if (m_compU) m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J);
1113 else m_naiveU.applyOnTheRight(firstCol, firstCol+i, J);
1121 template <
typename MatrixType>
1128 RealScalar c = m_computed(firstColm+i, firstColm);
1129 RealScalar s = m_computed(firstColm+j, firstColm);
1130 RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s));
1131 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1132 std::cout <<
"deflation 4.4: " << i <<
"," << j <<
" -> " << c <<
" " << s <<
" " << r <<
" ; "
1133 << m_computed(firstColm + i-1, firstColm) <<
" "
1134 << m_computed(firstColm + i, firstColm) <<
" "
1135 << m_computed(firstColm + i+1, firstColm) <<
" "
1136 << m_computed(firstColm + i+2, firstColm) <<
"\n";
1137 std::cout << m_computed(firstColm + i-1, firstColm + i-1) <<
" "
1138 << m_computed(firstColm + i, firstColm+i) <<
" "
1139 << m_computed(firstColm + i+1, firstColm+i+1) <<
" "
1140 << m_computed(firstColm + i+2, firstColm+i+2) <<
"\n";
1144 m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j);
1149 m_computed(firstColm + i, firstColm) = r;
1150 m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
1151 m_computed(firstColm + j, firstColm) = Literal(0);
1153 JacobiRotation<RealScalar> J(c,-s);
1154 if (m_compU) m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J);
1155 else m_naiveU.applyOnTheRight(firstColu+i, firstColu+j, J);
1156 if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J);
1161 template <
typename MatrixType>
1166 const Index length = lastCol + 1 - firstCol;
1168 Block<MatrixXr,Dynamic,1> col0(m_computed, firstCol+shift, firstCol+shift, length, 1);
1169 Diagonal<MatrixXr> fulldiag(m_computed);
1170 VectorBlock<Diagonal<MatrixXr>,
Dynamic> diag(fulldiag, firstCol+shift, length);
1172 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
1173 RealScalar maxDiag = diag.tail((std::max)(
Index(1),length-1)).cwiseAbs().maxCoeff();
1174 RealScalar epsilon_strict = numext::maxi<RealScalar>(considerZero,NumTraits<RealScalar>::epsilon() * maxDiag);
1175 RealScalar epsilon_coarse = Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(col0.cwiseAbs().maxCoeff(), maxDiag);
1177 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1178 assert(m_naiveU.allFinite());
1179 assert(m_naiveV.allFinite());
1180 assert(m_computed.allFinite());
1183 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1184 std::cout <<
"\ndeflate:" << diag.head(k+1).transpose() <<
" | " << diag.segment(k+1,length-k-1).transpose() <<
"\n";
1188 if (diag(0) < epsilon_coarse)
1190 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1191 std::cout <<
"deflation 4.1, because " << diag(0) <<
" < " << epsilon_coarse <<
"\n";
1193 diag(0) = epsilon_coarse;
1197 for (
Index i=1;i<length;++i)
1198 if (abs(col0(i)) < epsilon_strict)
1200 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1201 std::cout <<
"deflation 4.2, set z(" << i <<
") to zero because " << abs(col0(i)) <<
" < " << epsilon_strict <<
" (diag(" << i <<
")=" << diag(i) <<
")\n";
1203 col0(i) = Literal(0);
1207 for (
Index i=1;i<length; i++)
1208 if (diag(i) < epsilon_coarse)
1210 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1211 std::cout <<
"deflation 4.3, cancel z(" << i <<
")=" << col0(i) <<
" because diag(" << i <<
")=" << diag(i) <<
" < " << epsilon_coarse <<
"\n";
1213 deflation43(firstCol, shift, i, length);
1216 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1217 assert(m_naiveU.allFinite());
1218 assert(m_naiveV.allFinite());
1219 assert(m_computed.allFinite());
1221 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1222 std::cout <<
"to be sorted: " << diag.transpose() <<
"\n\n";
1223 std::cout <<
" : " << col0.transpose() <<
"\n\n";
1228 bool total_deflation = (col0.tail(length-1).array()<considerZero).all();
1232 Index *permutation = m_workspaceI.data();
1238 for(
Index i=1; i<length; ++i)
1239 if(abs(diag(i))<considerZero)
1240 permutation[p++] = i;
1243 for( ; p < length; ++p)
1245 if (i > k) permutation[p] = j++;
1246 else if (j >= length) permutation[p] = i++;
1247 else if (diag(i) < diag(j)) permutation[p] = j++;
1248 else permutation[p] = i++;
1255 for(
Index i=1; i<length; ++i)
1257 Index pi = permutation[i];
1258 if(abs(diag(pi))<considerZero || diag(0)<diag(pi))
1259 permutation[i-1] = permutation[i];
1262 permutation[i-1] = 0;
1269 Index *realInd = m_workspaceI.data()+length;
1270 Index *realCol = m_workspaceI.data()+2*length;
1272 for(
int pos = 0; pos< length; pos++)
1278 for(
Index i = total_deflation?0:1; i < length; i++)
1280 const Index pi = permutation[length - (total_deflation ? i+1 : i)];
1281 const Index J = realCol[pi];
1285 swap(diag(i), diag(J));
1286 if(i!=0 && J!=0) swap(col0(i), col0(J));
1289 if (m_compU) m_naiveU.col(firstCol+i).segment(firstCol, length + 1).swap(m_naiveU.col(firstCol+J).segment(firstCol, length + 1));
1290 else m_naiveU.col(firstCol+i).segment(0, 2) .swap(m_naiveU.col(firstCol+J).segment(0, 2));
1291 if (m_compV) m_naiveV.col(firstColW + i).segment(firstRowW, length).swap(m_naiveV.col(firstColW + J).segment(firstRowW, length));
1294 const Index realI = realInd[i];
1301 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1302 std::cout <<
"sorted: " << diag.transpose().format(bdcsvdfmt) <<
"\n";
1303 std::cout <<
" : " << col0.transpose() <<
"\n\n";
1309 while(i>0 && (abs(diag(i))<considerZero || abs(col0(i))<considerZero)) --i;
1311 if( (diag(i) - diag(i-1)) < NumTraits<RealScalar>::epsilon()*maxDiag )
1313 #ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
1314 std::cout <<
"deflation 4.4 with i = " << i <<
" because " << diag(i) <<
" - " << diag(i-1) <<
" == " << (diag(i) - diag(i-1)) <<
" < " << NumTraits<RealScalar>::epsilon()*maxDiag <<
"\n";
1316 eigen_internal_assert(abs(diag(i) - diag(i-1))<epsilon_coarse &&
" diagonal entries are not properly sorted");
1317 deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i-1, i, length);
1321 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1322 for(
Index j=2;j<length;++j)
1323 assert(diag(j-1)<=diag(j) || abs(diag(j))<considerZero);
1326 #ifdef EIGEN_BDCSVD_SANITY_CHECKS
1327 assert(m_naiveU.allFinite());
1328 assert(m_naiveV.allFinite());
1329 assert(m_computed.allFinite());
1333 #if !defined(EIGEN_GPUCC)
1340 template<
typename Derived>
1341 BDCSVD<typename MatrixBase<Derived>::PlainObject>