21#ifndef EIGEN_BDCSVD_IMPL_H
22#define EIGEN_BDCSVD_IMPL_H
25#include "./InternalHeaderCheck.h"
39template <
typename RealScalar_>
42 using RealScalar = RealScalar_;
43 using Literal =
typename NumTraits<RealScalar>::Literal;
44 using MatrixXr = Matrix<RealScalar, Dynamic, Dynamic, ColMajor>;
45 using VectorType = Matrix<RealScalar, Dynamic, 1>;
46 using ArrayXr = Array<RealScalar, Dynamic, 1>;
47 using ArrayXi = Array<Index, 1, Dynamic>;
48 using ArrayRef = Ref<ArrayXr>;
49 using ConstArrayRef = Ref<const ArrayXr>;
50 using IndicesRef = Ref<ArrayXi>;
52 bdcsvd_impl() : m_algoswap(16), m_compU(false), m_compV(false), m_numIters(0), m_info(
Success) {}
54 void allocate(Index diagSize,
bool compU,
bool compV);
57 void divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift);
60 void splitNegligibleSuperdiagonal(Index n);
62 MatrixXr& naiveU() {
return m_naiveU; }
63 const MatrixXr& naiveU()
const {
return m_naiveU; }
64 MatrixXr& naiveV() {
return m_naiveV; }
65 const MatrixXr& naiveV()
const {
return m_naiveV; }
66 MatrixXr& computed() {
return m_computed; }
67 const MatrixXr& computed()
const {
return m_computed; }
69 int numIters()
const {
return m_numIters; }
70 int algoSwap()
const {
return m_algoswap; }
71 void setAlgoSwap(
int s) { m_algoswap = s; }
74 void computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V);
75 void computeSingVals(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm, VectorType& singVals,
76 ArrayRef shifts, ArrayRef mus, ArrayRef workspace);
77 void perturbCol0(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm,
const VectorType& singVals,
78 const ArrayRef& shifts,
const ArrayRef& mus, ArrayRef zhat);
79 void computeSingVecs(
const ArrayRef& zhat,
const ArrayRef& diag,
const IndicesRef& perm,
const VectorType& singVals,
80 const ArrayRef& shifts,
const ArrayRef& mus, MatrixXr& U, MatrixXr& V);
81 void deflation43(Index firstCol, Index shift, Index i, Index size);
82 void deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size);
83 void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift);
84 void structured_update(Block<MatrixXr, Dynamic, Dynamic> A,
const MatrixXr& B, Index n1);
85 static EIGEN_STRONG_INLINE RealScalar productOfQuotients(RealScalar firstNumerator, RealScalar firstDenominator,
86 RealScalar secondNumerator, RealScalar secondDenominator);
87 static EIGEN_STRONG_INLINE RealScalar sequentialQuotient(RealScalar numerator, RealScalar firstDenominator,
88 RealScalar secondDenominator);
89 static RealScalar secularEq(RealScalar x,
const ConstArrayRef& col0,
const ConstArrayRef& diag,
90 const ConstArrayRef& diagShifted, RealScalar shift);
91 template <
typename SVDType>
92 void computeBaseCase(SVDType& svd, Index n, Index firstCol, Index firstRowW, Index firstColW, Index shift);
94 MatrixXr m_naiveU, m_naiveV;
100 JacobiSVD<MatrixXr, ComputeFullU> m_baseSvdU;
101 JacobiSVD<MatrixXr, ComputeFullU | ComputeFullV> m_baseSvdUV;
103 bool m_compU, m_compV;
108template <
typename RealScalar_>
109void bdcsvd_impl<RealScalar_>::allocate(Index diagSize,
bool compU,
bool compV) {
115 m_computed = MatrixXr::Zero(diagSize + 1, diagSize);
118 m_naiveU = MatrixXr::Zero(diagSize + 1, diagSize + 1);
120 m_naiveU = MatrixXr::Zero(2, diagSize + 1);
122 if (m_compV) m_naiveV = MatrixXr::Zero(diagSize, diagSize);
127 if (m_compU || m_compV)
128 m_workspace.resize((diagSize + 1) * (diagSize + 1) * 3);
130 m_workspace.resize(5 * diagSize);
131 m_workspaceI.resize(3 * diagSize);
139template <
typename RealScalar_>
140void bdcsvd_impl<RealScalar_>::splitNegligibleSuperdiagonal(Index n) {
145 const RealScalar norm = numext::maxi(m_computed.topRows(n).diagonal().cwiseAbs().maxCoeff(),
146 m_computed.topRows(n).template diagonal<-1>().cwiseAbs().maxCoeff());
147 const RealScalar threshold = RealScalar(0.45) * NumTraits<RealScalar>::epsilon() * norm;
148 for (Index i = 0; i + 1 < n; ++i)
149 if (numext::abs(m_computed(i + 1, i)) < threshold) m_computed(i + 1, i) = RealScalar(0);
160template <
typename RealScalar_>
161void bdcsvd_impl<RealScalar_>::structured_update(Block<MatrixXr, Dynamic, Dynamic> A,
const MatrixXr& B, Index n1) {
167 Map<MatrixXr> A1(m_workspace.data(), n1, n);
168 Map<MatrixXr> A2(m_workspace.data() + n1 * n, n2, n);
169 Map<MatrixXr> B1(m_workspace.data() + n * n, n, n);
170 Map<MatrixXr> B2(m_workspace.data() + 2 * n * n, n, n);
171 Index k1 = 0, k2 = 0;
172 for (Index j = 0; j < n; ++j) {
173 if ((A.col(j).head(n1).array() != Literal(0)).any()) {
174 A1.col(k1) = A.col(j).head(n1);
175 B1.row(k1) = B.row(j);
178 if ((A.col(j).tail(n2).array() != Literal(0)).any()) {
179 A2.col(k2) = A.col(j).tail(n2);
180 B2.row(k2) = B.row(j);
185 A.topRows(n1).noalias() = A1.leftCols(k1) * B1.topRows(k1);
186 A.bottomRows(n2).noalias() = A2.leftCols(k2) * B2.topRows(k2);
188 Map<MatrixXr, Aligned> tmp(m_workspace.data(), n, n);
189 tmp.noalias() = A * B;
194template <
typename RealScalar_>
195template <
typename SVDType>
196void bdcsvd_impl<RealScalar_>::computeBaseCase(SVDType& svd, Index n, Index firstCol, Index firstRowW, Index firstColW,
198 svd.compute(m_computed.block(firstCol, firstCol, n + 1, n));
202 m_naiveU.block(firstCol, firstCol, n + 1, n + 1) = svd.matrixU();
204 m_naiveU.row(0).segment(firstCol, n + 1) = svd.matrixU().row(0);
205 m_naiveU.row(1).segment(firstCol, n + 1) = svd.matrixU().row(n);
207 if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n) = svd.matrixV();
208 m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero();
209 m_computed.diagonal().segment(firstCol + shift, n) = svd.singularValues().head(n);
225template <
typename RealScalar_>
226void bdcsvd_impl<RealScalar_>::divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift) {
228 const Index n = lastCol - firstCol + 1;
229 const Index k = n / 2;
230 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
234 RealScalar lambda, phi, c0, s0;
237 if (n < m_algoswap) {
239 computeBaseCase(m_baseSvdUV, n, firstCol, firstRowW, firstColW, shift);
241 computeBaseCase(m_baseSvdU, n, firstCol, firstRowW, firstColW, shift);
246 alphaK = m_computed(firstCol + k, firstCol + k);
247 betaK = m_computed(firstCol + k + 1, firstCol + k);
251 divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift);
253 divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1);
257 lambda = m_naiveU(firstCol + k, firstCol + k);
258 phi = m_naiveU(firstCol + k + 1, lastCol + 1);
260 lambda = m_naiveU(1, firstCol + k);
261 phi = m_naiveU(0, lastCol + 1);
266 r0 = numext::hypot(alphaK * lambda, betaK * phi);
267 if (m_compV) m_naiveV(firstRowW + k, firstColW) = Literal(1);
268 if (r0 < considerZero) {
272 c0 = alphaK * lambda / r0;
273 s0 = betaK * phi / r0;
276 m_computed(firstCol + shift, firstCol + shift) = r0;
278 m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) =
279 alphaK * m_naiveU.row(firstCol + k).segment(firstCol, k).transpose();
280 m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) =
281 betaK * m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1).transpose();
283 m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) =
284 alphaK * m_naiveU.row(1).segment(firstCol, k).transpose();
285 m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) =
286 betaK * m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).transpose();
290 Map<VectorType, Aligned> q1(m_workspace.data(), k + 1);
291 q1 = m_naiveU.col(firstCol + k).segment(firstCol, k + 1);
293 for (Index i = firstCol + k - 1; i >= firstCol; i--)
294 m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1);
296 m_naiveU.col(firstCol).segment(firstCol, k + 1) = (q1 * c0);
298 m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * (-s0));
300 m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) =
301 m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0;
303 m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0;
305 RealScalar q1 = m_naiveU(0, firstCol + k);
307 for (Index i = firstCol + k - 1; i >= firstCol; i--) m_naiveU(0, i + 1) = m_naiveU(0, i);
309 m_naiveU(0, firstCol) = (q1 * c0);
311 m_naiveU(0, lastCol + 1) = (q1 * (-s0));
313 m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) * s0;
315 m_naiveU(1, lastCol + 1) *= c0;
316 m_naiveU.row(1).segment(firstCol + 1, k).setZero();
317 m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero();
321 deflation(firstCol, lastCol, k, firstRowW, firstColW, shift);
324 MatrixXr UofSVD, VofSVD;
326 computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD);
329 structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n + 2) / 2);
331 Map<Matrix<RealScalar, 2, Dynamic>,
Aligned> tmp(m_workspace.data(), 2, n + 1);
332 tmp.noalias() = m_naiveU.middleCols(firstCol, n + 1) * UofSVD;
333 m_naiveU.middleCols(firstCol, n + 1) = tmp;
336 if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n + 1) / 2);
340 m_computed.col(firstCol + shift).segment(firstCol + shift, n).setZero();
341 m_computed.diagonal().segment(firstCol + shift, n) = singVals;
348template <
typename RealScalar_>
349void bdcsvd_impl<RealScalar_>::computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals, MatrixXr& V) {
350 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
352 ArrayRef col0 = m_computed.col(firstCol).segment(firstCol, n);
353 m_workspace.head(n) = m_computed.block(firstCol, firstCol, n, n).diagonal();
354 ArrayRef diag = m_workspace.head(n);
355 diag(0) = Literal(0);
359 U.resize(n + 1, n + 1);
360 if (m_compV) V.resize(n, n);
366 while (actual_n > 1 && numext::is_exactly_zero(diag(actual_n - 1))) {
368 eigen_internal_assert(numext::is_exactly_zero(col0(actual_n)));
371 for (Index k = 0; k < actual_n; ++k)
372 if (abs(col0(k)) > considerZero) m_workspaceI(m++) = k;
373 Map<ArrayXi> perm(m_workspaceI.data(), m);
375 Map<ArrayXr> shifts(m_workspace.data() + 1 * n, n);
376 Map<ArrayXr> mus(m_workspace.data() + 2 * n, n);
377 Map<ArrayXr> zhat(m_workspace.data() + 3 * n, n);
381 Map<ArrayXr> secularWorkspace(U.data(), 2 * n);
382 computeSingVals(col0, diag, perm, singVals, shifts, mus, secularWorkspace);
385 perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat);
387 computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V);
391 for (Index i = 0; i < actual_n - 1; ++i) {
392 if (singVals(i) > singVals(i + 1)) {
394 swap(singVals(i), singVals(i + 1));
395 U.col(i).swap(U.col(i + 1));
396 if (m_compV) V.col(i).swap(V.col(i + 1));
402 singVals.head(actual_n).reverseInPlace();
403 U.leftCols(actual_n).rowwise().reverseInPlace();
404 if (m_compV) V.leftCols(actual_n).rowwise().reverseInPlace();
407template <
typename RealScalar_>
408EIGEN_STRONG_INLINE
typename bdcsvd_impl<RealScalar_>::RealScalar bdcsvd_impl<RealScalar_>::productOfQuotients(
409 RealScalar firstNumerator, RealScalar firstDenominator, RealScalar secondNumerator, RealScalar secondDenominator) {
411 RealScalar firstQuotient = firstNumerator / firstDenominator;
412 RealScalar secondQuotient = secondNumerator / secondDenominator;
413#if defined(__FAST_MATH__) || EIGEN_COMP_NVHPC
415 EIGEN_OPTIMIZATION_BARRIER(firstQuotient)
416 EIGEN_OPTIMIZATION_BARRIER(secondQuotient)
418 return firstQuotient * secondQuotient;
421template <
typename RealScalar_>
422EIGEN_STRONG_INLINE
typename bdcsvd_impl<RealScalar_>::RealScalar bdcsvd_impl<RealScalar_>::sequentialQuotient(
423 RealScalar numerator, RealScalar firstDenominator, RealScalar secondDenominator) {
424 RealScalar firstQuotient = numerator / firstDenominator;
425#if defined(__FAST_MATH__) || EIGEN_COMP_NVHPC
426 EIGEN_OPTIMIZATION_BARRIER(firstQuotient)
428 return firstQuotient / secondDenominator;
431template <
typename RealScalar_>
432typename bdcsvd_impl<RealScalar_>::RealScalar bdcsvd_impl<RealScalar_>::secularEq(RealScalar mu,
433 const ConstArrayRef& col0,
434 const ConstArrayRef& diag,
435 const ConstArrayRef& diagShifted,
437 RealScalar res = Literal(1);
438 for (Index i = 0; i < col0.size(); ++i) {
439 res += productOfQuotients(col0(i), diagShifted(i) - mu, col0(i), diag(i) + shift + mu);
444template <
typename RealScalar_>
445void bdcsvd_impl<RealScalar_>::computeSingVals(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm,
446 VectorType& singVals, ArrayRef shifts, ArrayRef mus,
447 ArrayRef workspace) {
454 Index n = col0.size();
455 const Index m = perm.size();
457 const bool contiguous = m == 0 || perm(m - 1) == m - 1;
459 for (Index i = 0; i < m; ++i) {
460 workspace(i) = col0(perm(i));
461 workspace(m + i) = diag(perm(i));
465 const ConstArrayRef activeCol0 = Map<const ArrayXr>(contiguous ? col0.data() : workspace.data(), m);
466 const ConstArrayRef activeDiag = Map<const ArrayXr>(contiguous ? diag.data() : workspace.data() + m, m);
470 while (actual_n > 1 && numext::is_exactly_zero(col0(actual_n - 1))) --actual_n;
472 for (Index k = 0; k < n; ++k) {
473 if (numext::is_exactly_zero(col0(k)) || actual_n == 1) {
476 singVals(k) = k == 0 ? col0(0) : diag(k);
478 shifts(k) = k == 0 ? col0(0) : diag(k);
483 RealScalar left = diag(k);
485 if (k == actual_n - 1)
486 right = (diag(actual_n - 1) + col0.matrix().stableNorm());
492 while (numext::is_exactly_zero(col0(l))) {
494 eigen_internal_assert(l < actual_n);
500 RealScalar mid = left + (right - left) / Literal(2);
501 RealScalar fMid = secularEq(mid, activeCol0, activeDiag, activeDiag, Literal(0));
502 RealScalar shift = (k == actual_n - 1 || fMid > Literal(0)) ? left : right;
505 Map<ArrayXr> diagShifted(m_workspace.data() + 4 * n, m);
506 const ConstArrayRef shiftedRef(diagShifted);
507 diagShifted = activeDiag - shift;
509 if (k != actual_n - 1) {
511 RealScalar midShifted = (right - left) / RealScalar(2);
513 if (numext::equal_strict(shift, right)) midShifted = -midShifted;
514 RealScalar fMidShifted = secularEq(midShifted, activeCol0, activeDiag, shiftedRef, shift);
515 if (fMidShifted > 0) {
517 shift = fMidShifted > Literal(0) ? left : right;
518 diagShifted = activeDiag - shift;
523 RealScalar muPrev, muCur;
525 if (numext::equal_strict(shift, left)) {
526 muPrev = (right - left) * RealScalar(0.1);
527 if (k == actual_n - 1)
528 muCur = right - left;
530 muCur = (right - left) * RealScalar(0.5);
532 muPrev = -(right - left) * RealScalar(0.1);
533 muCur = -(right - left) * RealScalar(0.5);
536 RealScalar fPrev = secularEq(muPrev, activeCol0, activeDiag, shiftedRef, shift);
537 RealScalar fCur = secularEq(muCur, activeCol0, activeDiag, shiftedRef, shift);
538 if (abs(fPrev) < abs(fCur)) {
546 const RealScalar minNormal = (std::numeric_limits<RealScalar>::min)();
547 bool useBisection = fPrev * fCur > Literal(0) && !(abs(fCur - fPrev) > NumTraits<RealScalar>::epsilon() &&
548 abs(fPrev) <= (std::numeric_limits<RealScalar>::max)() &&
549 abs(muPrev) >= minNormal && abs(muCur) >= minNormal);
550 while (!numext::is_exactly_zero(fCur) &&
551 abs(muCur - muPrev) >
552 Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(muCur), abs(muPrev)) &&
553 abs(fCur - fPrev) > NumTraits<RealScalar>::epsilon() && !useBisection) {
557 RealScalar a = (fCur - fPrev) / (Literal(1) / muCur - Literal(1) / muPrev);
558 RealScalar b = fCur - a / muCur;
560 RealScalar muZero = -a / b;
561 RealScalar fZero = secularEq(muZero, activeCol0, activeDiag, shiftedRef, shift);
569 if (numext::equal_strict(shift, left) && (muCur < Literal(0) || muCur > right - left)) useBisection =
true;
570 if (numext::equal_strict(shift, right) && (muCur < -(right - left) || muCur > Literal(0))) useBisection =
true;
571 if (abs(fCur) > abs(fPrev)) useBisection =
true;
576 RealScalar leftShifted, rightShifted;
578 if (numext::equal_strict(shift, left)) {
581 leftShifted = numext::maxi<RealScalar>(
582 (std::numeric_limits<RealScalar>::min)(),
583 Literal(2) * abs(col0(k)) / numext::sqrt((std::numeric_limits<RealScalar>::max)()));
586 eigen_internal_assert(
587 (numext::isfinite)(productOfQuotients(col0(k), leftShifted, col0(k), diag(k) + shift + leftShifted)));
588 rightShifted = (k == actual_n - 1)
590 : ((right - left) * RealScalar(0.51));
592 leftShifted = -(right - left) * RealScalar(0.51);
595 -numext::maxi<RealScalar>((std::numeric_limits<RealScalar>::min)(),
596 abs(col0(k + 1)) / numext::sqrt((std::numeric_limits<RealScalar>::max)()));
598 rightShifted = -(std::numeric_limits<RealScalar>::min)();
600 RealScalar fLeft = secularEq(leftShifted, activeCol0, activeDiag, shiftedRef, shift);
601 eigen_internal_assert(fLeft < Literal(0));
603 if (fLeft < Literal(0)) {
604 while (rightShifted - leftShifted > Literal(2) * NumTraits<RealScalar>::epsilon() *
605 numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted))) {
606 RealScalar midShifted = (leftShifted + rightShifted) / Literal(2);
607 fMid = secularEq(midShifted, activeCol0, activeDiag, shiftedRef, shift);
608 eigen_internal_assert((numext::isfinite)(fMid));
610 if (fLeft * fMid < Literal(0)) {
611 rightShifted = midShifted;
613 leftShifted = midShifted;
617 muCur = (leftShifted + rightShifted) / Literal(2);
623 muCur = (right - left) * RealScalar(0.5);
625 if (numext::equal_strict(shift, right)) muCur = -muCur;
629 singVals[k] = shift + muCur;
636template <
typename RealScalar_>
637void bdcsvd_impl<RealScalar_>::perturbCol0(
const ArrayRef& col0,
const ArrayRef& diag,
const IndicesRef& perm,
638 const VectorType& singVals,
const ArrayRef& shifts,
const ArrayRef& mus,
641 Index n = col0.size();
642 Index m = perm.size();
647 Index lastIdx = perm(m - 1);
649 for (Index k = 0; k < n; ++k) {
650 if (numext::is_exactly_zero(col0(k)))
651 zhat(k) = Literal(0);
654 RealScalar dk = diag(k);
658 RealScalar diff = shifts(lastIdx) - dk;
659 EIGEN_OPTIMIZATION_BARRIER(diff)
660 RealScalar prod = (singVals(lastIdx) + dk) * (mus(lastIdx) + diff);
662 for (Index l = 0; l < m; ++l) {
667 if (i >= k && l == 0) {
672 Index j = i < k ? i : perm(l - 1);
673 diff = shifts(j) - dk;
674 EIGEN_OPTIMIZATION_BARRIER(diff)
675 prod *= productOfQuotients(singVals(j) + dk, diag(i) + dk, mus(j) + diff, diag(i) - dk);
680 RealScalar tmp = numext::sqrt(numext::abs(prod));
681 zhat(k) = col0(k) > Literal(0) ? RealScalar(tmp) : RealScalar(-tmp);
687template <
typename RealScalar_>
688void bdcsvd_impl<RealScalar_>::computeSingVecs(
const ArrayRef& zhat,
const ArrayRef& diag,
const IndicesRef& perm,
689 const VectorType& singVals,
const ArrayRef& shifts,
const ArrayRef& mus,
690 MatrixXr& U, MatrixXr& V) {
691 Index n = zhat.size();
692 Index m = perm.size();
694 for (Index k = 0; k < n; ++k) {
695 if (numext::is_exactly_zero(zhat(k))) {
696 U.col(k) = VectorType::Unit(n + 1, k);
697 if (m_compV) V.col(k) = VectorType::Unit(n, k);
700 if (m_compV) V.col(k).setZero();
701 const RealScalar shift = shifts(k);
702 const RealScalar mu = mus(k);
703 const RealScalar singularValue = singVals(k);
704 for (Index l = 0; l < m; ++l) {
706 const RealScalar diagonal = diag(i);
707 const RealScalar z = zhat(i);
708 RealScalar diff = diagonal - shift;
709 EIGEN_OPTIMIZATION_BARRIER(diff)
711 EIGEN_OPTIMIZATION_BARRIER(diff)
712 const RealScalar sum = diagonal + singularValue;
713 U(i, k) = sequentialQuotient(z, diff, sum);
714 if (m_compV && l > 0) V(i, k) = sequentialQuotient(diagonal * z, diff, sum);
716 U(n, k) = Literal(0);
721 U.col(k).stableNormalize();
724 V(0, k) = Literal(-1);
725 V.col(k).stableNormalize();
729 U.col(n) = VectorType::Unit(n + 1, n);
735template <
typename RealScalar_>
736void bdcsvd_impl<RealScalar_>::deflation43(Index firstCol, Index shift, Index i, Index size) {
737 Index start = firstCol + shift;
738 RealScalar c = m_computed(start, start);
739 RealScalar s = m_computed(start + i, start);
740 RealScalar r = numext::hypot(c, s);
741 if (numext::is_exactly_zero(r)) {
742 m_computed(start + i, start + i) = Literal(0);
745 m_computed(start, start) = r;
746 m_computed(start + i, start) = Literal(0);
747 m_computed(start + i, start + i) = Literal(0);
749 JacobiRotation<RealScalar> J(c / r, -s / r);
751 m_naiveU.middleRows(firstCol, size + 1).applyOnTheRight(firstCol, firstCol + i, J);
753 m_naiveU.applyOnTheRight(firstCol, firstCol + i, J);
759template <
typename RealScalar_>
760void bdcsvd_impl<RealScalar_>::deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW, Index i,
761 Index j, Index size) {
762 RealScalar s = m_computed(firstColm + i, firstColm);
763 RealScalar c = m_computed(firstColm + j, firstColm);
764 RealScalar r = numext::hypot(c, s);
765 if (numext::is_exactly_zero(r)) {
766 m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
771 m_computed(firstColm + j, firstColm) = r;
772 m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
773 m_computed(firstColm + i, firstColm) = Literal(0);
775 JacobiRotation<RealScalar> J(c, -s);
777 m_naiveU.middleRows(firstColu, size + 1).applyOnTheRight(firstColu + j, firstColu + i, J);
779 m_naiveU.applyOnTheRight(firstColu + j, firstColu + i, J);
780 if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + j, firstColW + i, J);
784template <
typename RealScalar_>
785void bdcsvd_impl<RealScalar_>::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW,
788 const Index length = lastCol + 1 - firstCol;
790 Block<MatrixXr, Dynamic, 1> col0(m_computed, firstCol + shift, firstCol + shift, length, 1);
791 Diagonal<MatrixXr> fulldiag(m_computed);
792 VectorBlock<Diagonal<MatrixXr>, Dynamic> diag(fulldiag, firstCol + shift, length);
794 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
795 RealScalar maxDiag = diag.tail((std::max)(Index(1), length - 1)).cwiseAbs().maxCoeff();
796 RealScalar epsilon_strict = numext::maxi<RealScalar>(considerZero, NumTraits<RealScalar>::epsilon() * maxDiag);
797 RealScalar epsilon_coarse =
798 Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(col0.cwiseAbs().maxCoeff(), maxDiag);
801 if (diag(0) < epsilon_coarse) {
802 diag(0) = epsilon_coarse;
806 for (Index i = 1; i < length; ++i)
807 if (abs(col0(i)) < epsilon_strict) {
808 col0(i) = Literal(0);
812 for (Index i = 1; i < length; i++)
813 if (diag(i) < epsilon_coarse) {
814 deflation43(firstCol, shift, i, length);
820 const bool total_deflation = (col0.tail(length - 1).array().abs() < considerZero).all();
824 Index* permutation = m_workspaceI.data();
830 for (Index i = 1; i < length; ++i)
831 if (diag(i) < considerZero) permutation[p++] = i;
833 Index i = 1, j = k + 1;
834 for (; p < length; ++p) {
836 permutation[p] = j++;
837 else if (j >= length)
838 permutation[p] = i++;
839 else if (diag(i) < diag(j))
840 permutation[p] = j++;
842 permutation[p] = i++;
847 if (total_deflation) {
848 for (Index i = 1; i < length; ++i) {
849 Index pi = permutation[i];
850 if (diag(pi) < considerZero || diag(0) < diag(pi))
851 permutation[i - 1] = permutation[i];
853 permutation[i - 1] = 0;
860 Index* realInd = m_workspaceI.data() + length;
861 Index* realCol = m_workspaceI.data() + 2 * length;
863 for (
int pos = 0; pos < length; pos++) {
868 for (Index i = total_deflation ? 0 : 1; i < length; i++) {
869 const Index pi = permutation[length - (total_deflation ? i + 1 : i)];
870 const Index J = realCol[pi];
874 swap(diag(i), diag(J));
875 if (i != 0 && J != 0) swap(col0(i), col0(J));
879 m_naiveU.col(firstCol + i)
880 .segment(firstCol, length + 1)
881 .swap(m_naiveU.col(firstCol + J).segment(firstCol, length + 1));
883 m_naiveU.col(firstCol + i).segment(0, 2).swap(m_naiveU.col(firstCol + J).segment(0, 2));
885 m_naiveV.col(firstColW + i)
886 .segment(firstRowW, length)
887 .swap(m_naiveV.col(firstColW + J).segment(firstRowW, length));
890 const Index realI = realInd[i];
900 Index i = length - 1;
902 while (i > 0 && (diag(i) < considerZero || abs(col0(i)) < considerZero)) --i;
905 if ((diag(i) - diag(i - 1)) < epsilon_coarse) {
906 deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i, i - 1, length);
ComputationInfo
Definition Constants.h:455
@ Aligned
Definition Constants.h:243
@ NumericalIssue
Definition Constants.h:459
@ Success
Definition Constants.h:457
@ NoConvergence
Definition Constants.h:461