@smake/eigen 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/eigen/Eigen/AccelerateSupport +52 -0
- package/eigen/Eigen/Cholesky +18 -20
- package/eigen/Eigen/CholmodSupport +28 -28
- package/eigen/Eigen/Core +187 -120
- package/eigen/Eigen/Eigenvalues +16 -13
- package/eigen/Eigen/Geometry +18 -18
- package/eigen/Eigen/Householder +9 -7
- package/eigen/Eigen/IterativeLinearSolvers +8 -4
- package/eigen/Eigen/Jacobi +14 -13
- package/eigen/Eigen/KLUSupport +23 -21
- package/eigen/Eigen/LU +15 -16
- package/eigen/Eigen/MetisSupport +12 -12
- package/eigen/Eigen/OrderingMethods +54 -51
- package/eigen/Eigen/PaStiXSupport +23 -21
- package/eigen/Eigen/PardisoSupport +17 -14
- package/eigen/Eigen/QR +18 -20
- package/eigen/Eigen/QtAlignedMalloc +5 -12
- package/eigen/Eigen/SPQRSupport +21 -14
- package/eigen/Eigen/SVD +23 -17
- package/eigen/Eigen/Sparse +1 -2
- package/eigen/Eigen/SparseCholesky +18 -15
- package/eigen/Eigen/SparseCore +18 -17
- package/eigen/Eigen/SparseLU +9 -9
- package/eigen/Eigen/SparseQR +16 -14
- package/eigen/Eigen/StdDeque +5 -2
- package/eigen/Eigen/StdList +5 -2
- package/eigen/Eigen/StdVector +5 -2
- package/eigen/Eigen/SuperLUSupport +30 -24
- package/eigen/Eigen/ThreadPool +80 -0
- package/eigen/Eigen/UmfPackSupport +19 -17
- package/eigen/Eigen/Version +14 -0
- package/eigen/Eigen/src/AccelerateSupport/AccelerateSupport.h +423 -0
- package/eigen/Eigen/src/AccelerateSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Cholesky/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Cholesky/LDLT.h +366 -405
- package/eigen/Eigen/src/Cholesky/LLT.h +323 -367
- package/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h +81 -56
- package/eigen/Eigen/src/CholmodSupport/CholmodSupport.h +585 -529
- package/eigen/Eigen/src/CholmodSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Core/ArithmeticSequence.h +143 -317
- package/eigen/Eigen/src/Core/Array.h +329 -370
- package/eigen/Eigen/src/Core/ArrayBase.h +190 -203
- package/eigen/Eigen/src/Core/ArrayWrapper.h +126 -170
- package/eigen/Eigen/src/Core/Assign.h +30 -40
- package/eigen/Eigen/src/Core/AssignEvaluator.h +651 -604
- package/eigen/Eigen/src/Core/Assign_MKL.h +125 -120
- package/eigen/Eigen/src/Core/BandMatrix.h +267 -282
- package/eigen/Eigen/src/Core/Block.h +371 -390
- package/eigen/Eigen/src/Core/CommaInitializer.h +85 -100
- package/eigen/Eigen/src/Core/ConditionEstimator.h +51 -53
- package/eigen/Eigen/src/Core/CoreEvaluators.h +1214 -937
- package/eigen/Eigen/src/Core/CoreIterators.h +72 -63
- package/eigen/Eigen/src/Core/CwiseBinaryOp.h +112 -129
- package/eigen/Eigen/src/Core/CwiseNullaryOp.h +676 -702
- package/eigen/Eigen/src/Core/CwiseTernaryOp.h +77 -103
- package/eigen/Eigen/src/Core/CwiseUnaryOp.h +55 -67
- package/eigen/Eigen/src/Core/CwiseUnaryView.h +127 -92
- package/eigen/Eigen/src/Core/DenseBase.h +630 -658
- package/eigen/Eigen/src/Core/DenseCoeffsBase.h +511 -628
- package/eigen/Eigen/src/Core/DenseStorage.h +511 -590
- package/eigen/Eigen/src/Core/DeviceWrapper.h +153 -0
- package/eigen/Eigen/src/Core/Diagonal.h +168 -207
- package/eigen/Eigen/src/Core/DiagonalMatrix.h +346 -317
- package/eigen/Eigen/src/Core/DiagonalProduct.h +12 -10
- package/eigen/Eigen/src/Core/Dot.h +167 -217
- package/eigen/Eigen/src/Core/EigenBase.h +74 -85
- package/eigen/Eigen/src/Core/Fill.h +138 -0
- package/eigen/Eigen/src/Core/FindCoeff.h +464 -0
- package/eigen/Eigen/src/Core/ForceAlignedAccess.h +90 -113
- package/eigen/Eigen/src/Core/Fuzzy.h +82 -105
- package/eigen/Eigen/src/Core/GeneralProduct.h +315 -261
- package/eigen/Eigen/src/Core/GenericPacketMath.h +1182 -520
- package/eigen/Eigen/src/Core/GlobalFunctions.h +193 -157
- package/eigen/Eigen/src/Core/IO.h +131 -156
- package/eigen/Eigen/src/Core/IndexedView.h +209 -125
- package/eigen/Eigen/src/Core/InnerProduct.h +260 -0
- package/eigen/Eigen/src/Core/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Core/Inverse.h +50 -59
- package/eigen/Eigen/src/Core/Map.h +123 -141
- package/eigen/Eigen/src/Core/MapBase.h +255 -282
- package/eigen/Eigen/src/Core/MathFunctions.h +1247 -1201
- package/eigen/Eigen/src/Core/MathFunctionsImpl.h +162 -99
- package/eigen/Eigen/src/Core/Matrix.h +463 -494
- package/eigen/Eigen/src/Core/MatrixBase.h +468 -470
- package/eigen/Eigen/src/Core/NestByValue.h +58 -52
- package/eigen/Eigen/src/Core/NoAlias.h +79 -86
- package/eigen/Eigen/src/Core/NumTraits.h +206 -206
- package/eigen/Eigen/src/Core/PartialReduxEvaluator.h +163 -142
- package/eigen/Eigen/src/Core/PermutationMatrix.h +461 -511
- package/eigen/Eigen/src/Core/PlainObjectBase.h +858 -972
- package/eigen/Eigen/src/Core/Product.h +246 -130
- package/eigen/Eigen/src/Core/ProductEvaluators.h +779 -671
- package/eigen/Eigen/src/Core/Random.h +153 -164
- package/eigen/Eigen/src/Core/RandomImpl.h +262 -0
- package/eigen/Eigen/src/Core/RealView.h +250 -0
- package/eigen/Eigen/src/Core/Redux.h +334 -314
- package/eigen/Eigen/src/Core/Ref.h +259 -257
- package/eigen/Eigen/src/Core/Replicate.h +92 -104
- package/eigen/Eigen/src/Core/Reshaped.h +215 -271
- package/eigen/Eigen/src/Core/ReturnByValue.h +47 -55
- package/eigen/Eigen/src/Core/Reverse.h +133 -148
- package/eigen/Eigen/src/Core/Select.h +68 -140
- package/eigen/Eigen/src/Core/SelfAdjointView.h +254 -290
- package/eigen/Eigen/src/Core/SelfCwiseBinaryOp.h +23 -20
- package/eigen/Eigen/src/Core/SkewSymmetricMatrix3.h +382 -0
- package/eigen/Eigen/src/Core/Solve.h +88 -102
- package/eigen/Eigen/src/Core/SolveTriangular.h +126 -124
- package/eigen/Eigen/src/Core/SolverBase.h +132 -133
- package/eigen/Eigen/src/Core/StableNorm.h +113 -147
- package/eigen/Eigen/src/Core/StlIterators.h +404 -248
- package/eigen/Eigen/src/Core/Stride.h +90 -92
- package/eigen/Eigen/src/Core/Swap.h +70 -39
- package/eigen/Eigen/src/Core/Transpose.h +258 -295
- package/eigen/Eigen/src/Core/Transpositions.h +270 -333
- package/eigen/Eigen/src/Core/TriangularMatrix.h +642 -743
- package/eigen/Eigen/src/Core/VectorBlock.h +59 -72
- package/eigen/Eigen/src/Core/VectorwiseOp.h +653 -704
- package/eigen/Eigen/src/Core/Visitor.h +464 -308
- package/eigen/Eigen/src/Core/arch/AVX/Complex.h +380 -187
- package/eigen/Eigen/src/Core/arch/AVX/MathFunctions.h +65 -163
- package/eigen/Eigen/src/Core/arch/AVX/PacketMath.h +2145 -638
- package/eigen/Eigen/src/Core/arch/AVX/Reductions.h +353 -0
- package/eigen/Eigen/src/Core/arch/AVX/TypeCasting.h +253 -60
- package/eigen/Eigen/src/Core/arch/AVX512/Complex.h +278 -228
- package/eigen/Eigen/src/Core/arch/AVX512/GemmKernel.h +1245 -0
- package/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h +48 -269
- package/eigen/Eigen/src/Core/arch/AVX512/MathFunctionsFP16.h +75 -0
- package/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h +1597 -754
- package/eigen/Eigen/src/Core/arch/AVX512/PacketMathFP16.h +1413 -0
- package/eigen/Eigen/src/Core/arch/AVX512/Reductions.h +297 -0
- package/eigen/Eigen/src/Core/arch/AVX512/TrsmKernel.h +1167 -0
- package/eigen/Eigen/src/Core/arch/AVX512/TrsmUnrolls.inc +1219 -0
- package/eigen/Eigen/src/Core/arch/AVX512/TypeCasting.h +229 -41
- package/eigen/Eigen/src/Core/arch/AVX512/TypeCastingFP16.h +130 -0
- package/eigen/Eigen/src/Core/arch/AltiVec/Complex.h +420 -184
- package/eigen/Eigen/src/Core/arch/AltiVec/MathFunctions.h +40 -49
- package/eigen/Eigen/src/Core/arch/AltiVec/MatrixProduct.h +2962 -2213
- package/eigen/Eigen/src/Core/arch/AltiVec/MatrixProductCommon.h +196 -212
- package/eigen/Eigen/src/Core/arch/AltiVec/MatrixProductMMA.h +713 -441
- package/eigen/Eigen/src/Core/arch/AltiVec/MatrixProductMMAbfloat16.h +742 -0
- package/eigen/Eigen/src/Core/arch/AltiVec/MatrixVectorProduct.inc +2818 -0
- package/eigen/Eigen/src/Core/arch/AltiVec/PacketMath.h +2380 -1362
- package/eigen/Eigen/src/Core/arch/AltiVec/TypeCasting.h +153 -0
- package/eigen/Eigen/src/Core/arch/Default/BFloat16.h +390 -224
- package/eigen/Eigen/src/Core/arch/Default/ConjHelper.h +78 -67
- package/eigen/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +1784 -799
- package/eigen/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h +167 -50
- package/eigen/Eigen/src/Core/arch/Default/Half.h +528 -379
- package/eigen/Eigen/src/Core/arch/Default/Settings.h +10 -12
- package/eigen/Eigen/src/Core/arch/GPU/Complex.h +244 -0
- package/eigen/Eigen/src/Core/arch/GPU/MathFunctions.h +41 -40
- package/eigen/Eigen/src/Core/arch/GPU/PacketMath.h +550 -523
- package/eigen/Eigen/src/Core/arch/GPU/Tuple.h +268 -0
- package/eigen/Eigen/src/Core/arch/GPU/TypeCasting.h +27 -30
- package/eigen/Eigen/src/Core/arch/HIP/hcc/math_constants.h +8 -8
- package/eigen/Eigen/src/Core/arch/HVX/PacketMath.h +1088 -0
- package/eigen/Eigen/src/Core/arch/LSX/Complex.h +520 -0
- package/eigen/Eigen/src/Core/arch/LSX/GeneralBlockPanelKernel.h +23 -0
- package/eigen/Eigen/src/Core/arch/LSX/MathFunctions.h +43 -0
- package/eigen/Eigen/src/Core/arch/LSX/PacketMath.h +2866 -0
- package/eigen/Eigen/src/Core/arch/LSX/TypeCasting.h +526 -0
- package/eigen/Eigen/src/Core/arch/MSA/Complex.h +54 -82
- package/eigen/Eigen/src/Core/arch/MSA/MathFunctions.h +84 -92
- package/eigen/Eigen/src/Core/arch/MSA/PacketMath.h +51 -47
- package/eigen/Eigen/src/Core/arch/NEON/Complex.h +454 -306
- package/eigen/Eigen/src/Core/arch/NEON/GeneralBlockPanelKernel.h +175 -115
- package/eigen/Eigen/src/Core/arch/NEON/MathFunctions.h +23 -30
- package/eigen/Eigen/src/Core/arch/NEON/PacketMath.h +4366 -2857
- package/eigen/Eigen/src/Core/arch/NEON/TypeCasting.h +616 -393
- package/eigen/Eigen/src/Core/arch/NEON/UnaryFunctors.h +57 -0
- package/eigen/Eigen/src/Core/arch/SSE/Complex.h +350 -198
- package/eigen/Eigen/src/Core/arch/SSE/MathFunctions.h +38 -149
- package/eigen/Eigen/src/Core/arch/SSE/PacketMath.h +1791 -912
- package/eigen/Eigen/src/Core/arch/SSE/Reductions.h +324 -0
- package/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h +128 -40
- package/eigen/Eigen/src/Core/arch/SVE/MathFunctions.h +10 -6
- package/eigen/Eigen/src/Core/arch/SVE/PacketMath.h +156 -234
- package/eigen/Eigen/src/Core/arch/SVE/TypeCasting.h +6 -3
- package/eigen/Eigen/src/Core/arch/SYCL/InteropHeaders.h +27 -32
- package/eigen/Eigen/src/Core/arch/SYCL/MathFunctions.h +119 -117
- package/eigen/Eigen/src/Core/arch/SYCL/PacketMath.h +325 -419
- package/eigen/Eigen/src/Core/arch/SYCL/TypeCasting.h +15 -17
- package/eigen/Eigen/src/Core/arch/ZVector/Complex.h +325 -181
- package/eigen/Eigen/src/Core/arch/ZVector/MathFunctions.h +94 -83
- package/eigen/Eigen/src/Core/arch/ZVector/PacketMath.h +811 -458
- package/eigen/Eigen/src/Core/functors/AssignmentFunctors.h +121 -124
- package/eigen/Eigen/src/Core/functors/BinaryFunctors.h +576 -370
- package/eigen/Eigen/src/Core/functors/NullaryFunctors.h +194 -109
- package/eigen/Eigen/src/Core/functors/StlFunctors.h +95 -112
- package/eigen/Eigen/src/Core/functors/TernaryFunctors.h +34 -7
- package/eigen/Eigen/src/Core/functors/UnaryFunctors.h +1038 -749
- package/eigen/Eigen/src/Core/products/GeneralBlockPanelKernel.h +1883 -1375
- package/eigen/Eigen/src/Core/products/GeneralMatrixMatrix.h +312 -370
- package/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +189 -176
- package/eigen/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h +84 -81
- package/eigen/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h +154 -73
- package/eigen/Eigen/src/Core/products/GeneralMatrixVector.h +292 -337
- package/eigen/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h +80 -77
- package/eigen/Eigen/src/Core/products/Parallelizer.h +207 -105
- package/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +327 -388
- package/eigen/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h +206 -224
- package/eigen/Eigen/src/Core/products/SelfadjointMatrixVector.h +138 -147
- package/eigen/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h +58 -61
- package/eigen/Eigen/src/Core/products/SelfadjointProduct.h +71 -71
- package/eigen/Eigen/src/Core/products/SelfadjointRank2Update.h +48 -47
- package/eigen/Eigen/src/Core/products/TriangularMatrixMatrix.h +294 -369
- package/eigen/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h +246 -238
- package/eigen/Eigen/src/Core/products/TriangularMatrixVector.h +244 -247
- package/eigen/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h +212 -192
- package/eigen/Eigen/src/Core/products/TriangularSolverMatrix.h +328 -277
- package/eigen/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h +108 -109
- package/eigen/Eigen/src/Core/products/TriangularSolverVector.h +68 -94
- package/eigen/Eigen/src/Core/util/Assert.h +158 -0
- package/eigen/Eigen/src/Core/util/BlasUtil.h +342 -303
- package/eigen/Eigen/src/Core/util/ConfigureVectorization.h +348 -317
- package/eigen/Eigen/src/Core/util/Constants.h +297 -262
- package/eigen/Eigen/src/Core/util/DisableStupidWarnings.h +130 -90
- package/eigen/Eigen/src/Core/util/EmulateArray.h +270 -0
- package/eigen/Eigen/src/Core/util/ForwardDeclarations.h +449 -247
- package/eigen/Eigen/src/Core/util/GpuHipCudaDefines.inc +101 -0
- package/eigen/Eigen/src/Core/util/GpuHipCudaUndefines.inc +45 -0
- package/eigen/Eigen/src/Core/util/IndexedViewHelper.h +417 -116
- package/eigen/Eigen/src/Core/util/IntegralConstant.h +211 -204
- package/eigen/Eigen/src/Core/util/MKL_support.h +39 -37
- package/eigen/Eigen/src/Core/util/Macros.h +655 -773
- package/eigen/Eigen/src/Core/util/MaxSizeVector.h +139 -0
- package/eigen/Eigen/src/Core/util/Memory.h +970 -748
- package/eigen/Eigen/src/Core/util/Meta.h +581 -633
- package/eigen/Eigen/src/Core/util/MoreMeta.h +638 -0
- package/eigen/Eigen/src/Core/util/ReenableStupidWarnings.h +32 -19
- package/eigen/Eigen/src/Core/util/ReshapedHelper.h +17 -17
- package/eigen/Eigen/src/Core/util/Serializer.h +209 -0
- package/eigen/Eigen/src/Core/util/StaticAssert.h +50 -166
- package/eigen/Eigen/src/Core/util/SymbolicIndex.h +377 -225
- package/eigen/Eigen/src/Core/util/XprHelper.h +784 -547
- package/eigen/Eigen/src/Eigenvalues/ComplexEigenSolver.h +246 -277
- package/eigen/Eigen/src/Eigenvalues/ComplexSchur.h +299 -319
- package/eigen/Eigen/src/Eigenvalues/ComplexSchur_LAPACKE.h +52 -48
- package/eigen/Eigen/src/Eigenvalues/EigenSolver.h +413 -456
- package/eigen/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +309 -325
- package/eigen/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +157 -171
- package/eigen/Eigen/src/Eigenvalues/HessenbergDecomposition.h +292 -310
- package/eigen/Eigen/src/Eigenvalues/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +89 -105
- package/eigen/Eigen/src/Eigenvalues/RealQZ.h +537 -607
- package/eigen/Eigen/src/Eigenvalues/RealSchur.h +342 -381
- package/eigen/Eigen/src/Eigenvalues/RealSchur_LAPACKE.h +41 -35
- package/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +541 -595
- package/eigen/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h +47 -44
- package/eigen/Eigen/src/Eigenvalues/Tridiagonalization.h +430 -462
- package/eigen/Eigen/src/Geometry/AlignedBox.h +226 -227
- package/eigen/Eigen/src/Geometry/AngleAxis.h +131 -133
- package/eigen/Eigen/src/Geometry/EulerAngles.h +163 -74
- package/eigen/Eigen/src/Geometry/Homogeneous.h +285 -333
- package/eigen/Eigen/src/Geometry/Hyperplane.h +151 -160
- package/eigen/Eigen/src/Geometry/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Geometry/OrthoMethods.h +168 -146
- package/eigen/Eigen/src/Geometry/ParametrizedLine.h +127 -127
- package/eigen/Eigen/src/Geometry/Quaternion.h +566 -506
- package/eigen/Eigen/src/Geometry/Rotation2D.h +107 -105
- package/eigen/Eigen/src/Geometry/RotationBase.h +148 -145
- package/eigen/Eigen/src/Geometry/Scaling.h +113 -106
- package/eigen/Eigen/src/Geometry/Transform.h +858 -936
- package/eigen/Eigen/src/Geometry/Translation.h +94 -92
- package/eigen/Eigen/src/Geometry/Umeyama.h +79 -84
- package/eigen/Eigen/src/Geometry/arch/Geometry_SIMD.h +90 -104
- package/eigen/Eigen/src/Householder/BlockHouseholder.h +51 -46
- package/eigen/Eigen/src/Householder/Householder.h +102 -124
- package/eigen/Eigen/src/Householder/HouseholderSequence.h +412 -453
- package/eigen/Eigen/src/Householder/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +149 -162
- package/eigen/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +124 -119
- package/eigen/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +92 -104
- package/eigen/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h +251 -243
- package/eigen/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +224 -228
- package/eigen/Eigen/src/IterativeLinearSolvers/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +178 -227
- package/eigen/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h +79 -84
- package/eigen/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +54 -60
- package/eigen/Eigen/src/Jacobi/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/Jacobi/Jacobi.h +252 -308
- package/eigen/Eigen/src/KLUSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/KLUSupport/KLUSupport.h +208 -227
- package/eigen/Eigen/src/LU/Determinant.h +50 -69
- package/eigen/Eigen/src/LU/FullPivLU.h +545 -596
- package/eigen/Eigen/src/LU/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/LU/InverseImpl.h +206 -285
- package/eigen/Eigen/src/LU/PartialPivLU.h +390 -428
- package/eigen/Eigen/src/LU/PartialPivLU_LAPACKE.h +54 -40
- package/eigen/Eigen/src/LU/arch/InverseSize4.h +72 -70
- package/eigen/Eigen/src/MetisSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/MetisSupport/MetisSupport.h +81 -93
- package/eigen/Eigen/src/OrderingMethods/Amd.h +243 -265
- package/eigen/Eigen/src/OrderingMethods/Eigen_Colamd.h +831 -1004
- package/eigen/Eigen/src/OrderingMethods/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/OrderingMethods/Ordering.h +112 -119
- package/eigen/Eigen/src/PaStiXSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/PaStiXSupport/PaStiXSupport.h +524 -570
- package/eigen/Eigen/src/PardisoSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/PardisoSupport/PardisoSupport.h +385 -430
- package/eigen/Eigen/src/QR/ColPivHouseholderQR.h +479 -479
- package/eigen/Eigen/src/QR/ColPivHouseholderQR_LAPACKE.h +120 -56
- package/eigen/Eigen/src/QR/CompleteOrthogonalDecomposition.h +166 -153
- package/eigen/Eigen/src/QR/FullPivHouseholderQR.h +495 -475
- package/eigen/Eigen/src/QR/HouseholderQR.h +394 -285
- package/eigen/Eigen/src/QR/HouseholderQR_LAPACKE.h +32 -23
- package/eigen/Eigen/src/QR/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SPQRSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +244 -264
- package/eigen/Eigen/src/SVD/BDCSVD.h +817 -713
- package/eigen/Eigen/src/SVD/BDCSVD_LAPACKE.h +174 -0
- package/eigen/Eigen/src/SVD/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SVD/JacobiSVD.h +577 -543
- package/eigen/Eigen/src/SVD/JacobiSVD_LAPACKE.h +85 -49
- package/eigen/Eigen/src/SVD/SVDBase.h +242 -182
- package/eigen/Eigen/src/SVD/UpperBidiagonalization.h +200 -235
- package/eigen/Eigen/src/SparseCholesky/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SparseCholesky/SimplicialCholesky.h +765 -594
- package/eigen/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +308 -94
- package/eigen/Eigen/src/SparseCore/AmbiVector.h +202 -251
- package/eigen/Eigen/src/SparseCore/CompressedStorage.h +184 -252
- package/eigen/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +134 -178
- package/eigen/Eigen/src/SparseCore/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SparseCore/SparseAssign.h +149 -140
- package/eigen/Eigen/src/SparseCore/SparseBlock.h +403 -440
- package/eigen/Eigen/src/SparseCore/SparseColEtree.h +100 -112
- package/eigen/Eigen/src/SparseCore/SparseCompressedBase.h +525 -303
- package/eigen/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +555 -339
- package/eigen/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +100 -108
- package/eigen/Eigen/src/SparseCore/SparseDenseProduct.h +169 -197
- package/eigen/Eigen/src/SparseCore/SparseDiagonalProduct.h +71 -71
- package/eigen/Eigen/src/SparseCore/SparseDot.h +49 -47
- package/eigen/Eigen/src/SparseCore/SparseFuzzy.h +13 -11
- package/eigen/Eigen/src/SparseCore/SparseMap.h +243 -253
- package/eigen/Eigen/src/SparseCore/SparseMatrix.h +1603 -1245
- package/eigen/Eigen/src/SparseCore/SparseMatrixBase.h +403 -350
- package/eigen/Eigen/src/SparseCore/SparsePermutation.h +186 -115
- package/eigen/Eigen/src/SparseCore/SparseProduct.h +94 -97
- package/eigen/Eigen/src/SparseCore/SparseRedux.h +22 -24
- package/eigen/Eigen/src/SparseCore/SparseRef.h +268 -295
- package/eigen/Eigen/src/SparseCore/SparseSelfAdjointView.h +370 -416
- package/eigen/Eigen/src/SparseCore/SparseSolverBase.h +78 -87
- package/eigen/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +81 -95
- package/eigen/Eigen/src/SparseCore/SparseTranspose.h +62 -71
- package/eigen/Eigen/src/SparseCore/SparseTriangularView.h +132 -144
- package/eigen/Eigen/src/SparseCore/SparseUtil.h +138 -115
- package/eigen/Eigen/src/SparseCore/SparseVector.h +426 -372
- package/eigen/Eigen/src/SparseCore/SparseView.h +164 -193
- package/eigen/Eigen/src/SparseCore/TriangularSolver.h +129 -170
- package/eigen/Eigen/src/SparseLU/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SparseLU/SparseLU.h +756 -710
- package/eigen/Eigen/src/SparseLU/SparseLUImpl.h +61 -48
- package/eigen/Eigen/src/SparseLU/SparseLU_Memory.h +102 -118
- package/eigen/Eigen/src/SparseLU/SparseLU_Structs.h +38 -35
- package/eigen/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +245 -301
- package/eigen/Eigen/src/SparseLU/SparseLU_Utils.h +44 -49
- package/eigen/Eigen/src/SparseLU/SparseLU_column_bmod.h +104 -108
- package/eigen/Eigen/src/SparseLU/SparseLU_column_dfs.h +89 -100
- package/eigen/Eigen/src/SparseLU/SparseLU_copy_to_ucol.h +57 -58
- package/eigen/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h +43 -55
- package/eigen/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +74 -71
- package/eigen/Eigen/src/SparseLU/SparseLU_panel_bmod.h +124 -132
- package/eigen/Eigen/src/SparseLU/SparseLU_panel_dfs.h +136 -159
- package/eigen/Eigen/src/SparseLU/SparseLU_pivotL.h +51 -52
- package/eigen/Eigen/src/SparseLU/SparseLU_pruneL.h +67 -73
- package/eigen/Eigen/src/SparseLU/SparseLU_relax_snode.h +24 -26
- package/eigen/Eigen/src/SparseQR/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SparseQR/SparseQR.h +450 -502
- package/eigen/Eigen/src/StlSupport/StdDeque.h +28 -93
- package/eigen/Eigen/src/StlSupport/StdList.h +28 -84
- package/eigen/Eigen/src/StlSupport/StdVector.h +28 -108
- package/eigen/Eigen/src/StlSupport/details.h +48 -50
- package/eigen/Eigen/src/SuperLUSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/SuperLUSupport/SuperLUSupport.h +634 -730
- package/eigen/Eigen/src/ThreadPool/Barrier.h +70 -0
- package/eigen/Eigen/src/ThreadPool/CoreThreadPoolDevice.h +336 -0
- package/eigen/Eigen/src/ThreadPool/EventCount.h +241 -0
- package/eigen/Eigen/src/ThreadPool/ForkJoin.h +140 -0
- package/eigen/Eigen/src/ThreadPool/InternalHeaderCheck.h +4 -0
- package/eigen/Eigen/src/ThreadPool/NonBlockingThreadPool.h +587 -0
- package/eigen/Eigen/src/ThreadPool/RunQueue.h +230 -0
- package/eigen/Eigen/src/ThreadPool/ThreadCancel.h +21 -0
- package/eigen/Eigen/src/ThreadPool/ThreadEnvironment.h +43 -0
- package/eigen/Eigen/src/ThreadPool/ThreadLocal.h +289 -0
- package/eigen/Eigen/src/ThreadPool/ThreadPoolInterface.h +50 -0
- package/eigen/Eigen/src/ThreadPool/ThreadYield.h +16 -0
- package/eigen/Eigen/src/UmfPackSupport/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/UmfPackSupport/UmfPackSupport.h +428 -464
- package/eigen/Eigen/src/misc/Image.h +41 -43
- package/eigen/Eigen/src/misc/InternalHeaderCheck.h +3 -0
- package/eigen/Eigen/src/misc/Kernel.h +39 -41
- package/eigen/Eigen/src/misc/RealSvd2x2.h +19 -21
- package/eigen/Eigen/src/misc/blas.h +83 -426
- package/eigen/Eigen/src/misc/lapacke.h +9972 -16179
- package/eigen/Eigen/src/misc/lapacke_helpers.h +163 -0
- package/eigen/Eigen/src/misc/lapacke_mangling.h +4 -5
- package/eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.inc +344 -0
- package/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.inc +544 -0
- package/eigen/Eigen/src/plugins/{BlockMethods.h → BlockMethods.inc} +434 -506
- package/eigen/Eigen/src/plugins/CommonCwiseBinaryOps.inc +116 -0
- package/eigen/Eigen/src/plugins/{CommonCwiseUnaryOps.h → CommonCwiseUnaryOps.inc} +58 -68
- package/eigen/Eigen/src/plugins/IndexedViewMethods.inc +192 -0
- package/eigen/Eigen/src/plugins/InternalHeaderCheck.inc +3 -0
- package/eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.inc +331 -0
- package/eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.inc +118 -0
- package/eigen/Eigen/src/plugins/ReshapedMethods.inc +133 -0
- package/package.json +1 -1
- package/eigen/COPYING.APACHE +0 -203
- package/eigen/COPYING.BSD +0 -26
- package/eigen/COPYING.GPL +0 -674
- package/eigen/COPYING.LGPL +0 -502
- package/eigen/COPYING.MINPACK +0 -51
- package/eigen/COPYING.MPL2 +0 -373
- package/eigen/COPYING.README +0 -18
- package/eigen/Eigen/src/Core/BooleanRedux.h +0 -162
- package/eigen/Eigen/src/Core/arch/CUDA/Complex.h +0 -258
- package/eigen/Eigen/src/Core/arch/Default/TypeCasting.h +0 -120
- package/eigen/Eigen/src/Core/arch/SYCL/SyclMemoryModel.h +0 -694
- package/eigen/Eigen/src/Core/util/NonMPL2.h +0 -3
- package/eigen/Eigen/src/SparseCore/MappedSparseMatrix.h +0 -67
- package/eigen/Eigen/src/SparseLU/SparseLU_gemm_kernel.h +0 -280
- package/eigen/Eigen/src/misc/lapack.h +0 -152
- package/eigen/Eigen/src/plugins/ArrayCwiseBinaryOps.h +0 -358
- package/eigen/Eigen/src/plugins/ArrayCwiseUnaryOps.h +0 -696
- package/eigen/Eigen/src/plugins/CommonCwiseBinaryOps.h +0 -115
- package/eigen/Eigen/src/plugins/IndexedViewMethods.h +0 -262
- package/eigen/Eigen/src/plugins/MatrixCwiseBinaryOps.h +0 -152
- package/eigen/Eigen/src/plugins/MatrixCwiseUnaryOps.h +0 -95
- package/eigen/Eigen/src/plugins/ReshapedMethods.h +0 -149
- package/eigen/README.md +0 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is part of Eigen, a lightweight C++ template library
|
|
2
2
|
// for linear algebra.
|
|
3
|
-
//
|
|
3
|
+
//
|
|
4
4
|
// We used the "A Divide-And-Conquer Algorithm for the Bidiagonal SVD"
|
|
5
5
|
// research report written by Ming Gu and Stanley C.Eisenstat
|
|
6
|
-
// The code variable names correspond to the names they used in their
|
|
6
|
+
// The code variable names correspond to the names they used in their
|
|
7
7
|
// report
|
|
8
8
|
//
|
|
9
9
|
// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com>
|
|
@@ -27,26 +27,31 @@
|
|
|
27
27
|
#define eigen_internal_assert(X) assert(X);
|
|
28
28
|
#endif
|
|
29
29
|
|
|
30
|
+
// IWYU pragma: private
|
|
31
|
+
#include "./InternalHeaderCheck.h"
|
|
32
|
+
|
|
33
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
34
|
+
#include <iostream>
|
|
35
|
+
#endif
|
|
36
|
+
|
|
30
37
|
namespace Eigen {
|
|
31
38
|
|
|
32
39
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
33
40
|
IOFormat bdcsvdfmt(8, 0, ", ", "\n", " [", "]");
|
|
34
41
|
#endif
|
|
35
|
-
|
|
36
|
-
template<typename
|
|
42
|
+
|
|
43
|
+
template <typename MatrixType_, int Options>
|
|
44
|
+
class BDCSVD;
|
|
37
45
|
|
|
38
46
|
namespace internal {
|
|
39
47
|
|
|
40
|
-
template<typename
|
|
41
|
-
struct traits<BDCSVD<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
48
|
+
template <typename MatrixType_, int Options>
|
|
49
|
+
struct traits<BDCSVD<MatrixType_, Options> > : svd_traits<MatrixType_, Options> {
|
|
50
|
+
typedef MatrixType_ MatrixType;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
} // end namespace internal
|
|
46
54
|
|
|
47
|
-
} // end namespace internal
|
|
48
|
-
|
|
49
|
-
|
|
50
55
|
/** \ingroup SVD_Module
|
|
51
56
|
*
|
|
52
57
|
*
|
|
@@ -54,7 +59,14 @@ struct traits<BDCSVD<_MatrixType> >
|
|
|
54
59
|
*
|
|
55
60
|
* \brief class Bidiagonal Divide and Conquer SVD
|
|
56
61
|
*
|
|
57
|
-
* \tparam
|
|
62
|
+
* \tparam MatrixType_ the type of the matrix of which we are computing the SVD decomposition
|
|
63
|
+
*
|
|
64
|
+
* \tparam Options_ this optional parameter allows one to specify options for computing unitaries \a U and \a V.
|
|
65
|
+
* Possible values are #ComputeThinU, #ComputeThinV, #ComputeFullU, #ComputeFullV, and
|
|
66
|
+
* #DisableQRDecomposition. It is not possible to request both the thin and full version of \a U or
|
|
67
|
+
* \a V. By default, unitaries are not computed. BDCSVD uses R-Bidiagonalization to improve
|
|
68
|
+
* performance on tall and wide matrices. For backwards compatility, the option
|
|
69
|
+
* #DisableQRDecomposition can be used to disable this optimization.
|
|
58
70
|
*
|
|
59
71
|
* This class first reduces the input matrix to bi-diagonal form using class UpperBidiagonalization,
|
|
60
72
|
* and then performs a divide-and-conquer diagonalization. Small blocks are diagonalized using class JacobiSVD.
|
|
@@ -69,40 +81,44 @@ struct traits<BDCSVD<_MatrixType> >
|
|
|
69
81
|
*
|
|
70
82
|
* \sa class JacobiSVD
|
|
71
83
|
*/
|
|
72
|
-
template<typename
|
|
73
|
-
class BDCSVD : public SVDBase<BDCSVD<
|
|
74
|
-
{
|
|
84
|
+
template <typename MatrixType_, int Options_>
|
|
85
|
+
class BDCSVD : public SVDBase<BDCSVD<MatrixType_, Options_> > {
|
|
75
86
|
typedef SVDBase<BDCSVD> Base;
|
|
76
|
-
|
|
77
|
-
public:
|
|
78
|
-
using Base::rows;
|
|
87
|
+
|
|
88
|
+
public:
|
|
79
89
|
using Base::cols;
|
|
80
90
|
using Base::computeU;
|
|
81
91
|
using Base::computeV;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
typedef
|
|
92
|
+
using Base::diagSize;
|
|
93
|
+
using Base::rows;
|
|
94
|
+
|
|
95
|
+
typedef MatrixType_ MatrixType;
|
|
96
|
+
typedef typename Base::Scalar Scalar;
|
|
97
|
+
typedef typename Base::RealScalar RealScalar;
|
|
86
98
|
typedef typename NumTraits<RealScalar>::Literal Literal;
|
|
99
|
+
typedef typename Base::Index Index;
|
|
87
100
|
enum {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
Options = Options_,
|
|
102
|
+
QRDecomposition = Options & internal::QRPreconditionerBits,
|
|
103
|
+
ComputationOptions = Options & internal::ComputationOptionsBits,
|
|
104
|
+
RowsAtCompileTime = Base::RowsAtCompileTime,
|
|
105
|
+
ColsAtCompileTime = Base::ColsAtCompileTime,
|
|
106
|
+
DiagSizeAtCompileTime = Base::DiagSizeAtCompileTime,
|
|
107
|
+
MaxRowsAtCompileTime = Base::MaxRowsAtCompileTime,
|
|
108
|
+
MaxColsAtCompileTime = Base::MaxColsAtCompileTime,
|
|
109
|
+
MaxDiagSizeAtCompileTime = Base::MaxDiagSizeAtCompileTime,
|
|
110
|
+
MatrixOptions = Base::MatrixOptions
|
|
95
111
|
};
|
|
96
112
|
|
|
97
113
|
typedef typename Base::MatrixUType MatrixUType;
|
|
98
114
|
typedef typename Base::MatrixVType MatrixVType;
|
|
99
115
|
typedef typename Base::SingularValuesType SingularValuesType;
|
|
100
|
-
|
|
116
|
+
|
|
101
117
|
typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> MatrixX;
|
|
102
118
|
typedef Matrix<RealScalar, Dynamic, Dynamic, ColMajor> MatrixXr;
|
|
103
119
|
typedef Matrix<RealScalar, Dynamic, 1> VectorType;
|
|
104
120
|
typedef Array<RealScalar, Dynamic, 1> ArrayXr;
|
|
105
|
-
typedef Array<Index,1,Dynamic> ArrayXi;
|
|
121
|
+
typedef Array<Index, 1, Dynamic> ArrayXi;
|
|
106
122
|
typedef Ref<ArrayXr> ArrayRef;
|
|
107
123
|
typedef Ref<ArrayXi> IndicesRef;
|
|
108
124
|
|
|
@@ -111,163 +127,227 @@ public:
|
|
|
111
127
|
* The default constructor is useful in cases in which the user intends to
|
|
112
128
|
* perform decompositions via BDCSVD::compute(const MatrixType&).
|
|
113
129
|
*/
|
|
114
|
-
BDCSVD() : m_algoswap(16), m_isTranspose(false), m_compU(false), m_compV(false), m_numIters(0)
|
|
115
|
-
{}
|
|
130
|
+
BDCSVD() : m_algoswap(16), m_isTranspose(false), m_compU(false), m_compV(false), m_numIters(0) {}
|
|
116
131
|
|
|
132
|
+
/** \brief Default Constructor with memory preallocation
|
|
133
|
+
*
|
|
134
|
+
* Like the default constructor but with preallocation of the internal data
|
|
135
|
+
* according to the specified problem size and \a Options template parameter.
|
|
136
|
+
* \sa BDCSVD()
|
|
137
|
+
*/
|
|
138
|
+
BDCSVD(Index rows, Index cols) : m_algoswap(16), m_numIters(0) {
|
|
139
|
+
allocate(rows, cols, internal::get_computation_options(Options));
|
|
140
|
+
}
|
|
117
141
|
|
|
118
142
|
/** \brief Default Constructor with memory preallocation
|
|
119
143
|
*
|
|
120
144
|
* Like the default constructor but with preallocation of the internal data
|
|
121
|
-
* according to the specified problem size.
|
|
145
|
+
* according to the specified problem size and the \a computationOptions.
|
|
146
|
+
*
|
|
147
|
+
* One \b cannot request unitaries using both the \a Options template parameter
|
|
148
|
+
* and the constructor. If possible, prefer using the \a Options template parameter.
|
|
149
|
+
*
|
|
150
|
+
* \param rows number of rows for the input matrix
|
|
151
|
+
* \param cols number of columns for the input matrix
|
|
152
|
+
* \param computationOptions specification for computing Thin/Full unitaries U/V
|
|
122
153
|
* \sa BDCSVD()
|
|
154
|
+
*
|
|
155
|
+
* \deprecated Will be removed in the next major Eigen version. Options should
|
|
156
|
+
* be specified in the \a Options template parameter.
|
|
123
157
|
*/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
158
|
+
EIGEN_DEPRECATED_WITH_REASON("Options should be specified using the class template parameter.")
|
|
159
|
+
BDCSVD(Index rows, Index cols, unsigned int computationOptions) : m_algoswap(16), m_numIters(0) {
|
|
160
|
+
internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, rows, cols);
|
|
127
161
|
allocate(rows, cols, computationOptions);
|
|
128
162
|
}
|
|
129
163
|
|
|
130
|
-
/** \brief Constructor performing the decomposition of given matrix
|
|
164
|
+
/** \brief Constructor performing the decomposition of given matrix, using the custom options specified
|
|
165
|
+
* with the \a Options template parameter.
|
|
131
166
|
*
|
|
132
167
|
* \param matrix the matrix to decompose
|
|
133
|
-
* \param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed.
|
|
134
|
-
* By default, none is computed. This is a bit - field, the possible bits are #ComputeFullU, #ComputeThinU,
|
|
135
|
-
* #ComputeFullV, #ComputeThinV.
|
|
136
|
-
*
|
|
137
|
-
* Thin unitaries are only available if your matrix type has a Dynamic number of columns (for example MatrixXf). They also are not
|
|
138
|
-
* available with the (non - default) FullPivHouseholderQR preconditioner.
|
|
139
168
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
compute(matrix, computationOptions);
|
|
169
|
+
template <typename Derived>
|
|
170
|
+
BDCSVD(const MatrixBase<Derived>& matrix) : m_algoswap(16), m_numIters(0) {
|
|
171
|
+
compute_impl(matrix, internal::get_computation_options(Options));
|
|
144
172
|
}
|
|
145
173
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
/** \brief Constructor performing the decomposition of given matrix using specified options
|
|
175
|
+
* for computing unitaries.
|
|
176
|
+
*
|
|
177
|
+
* One \b cannot request unitaries using both the \a Options template parameter
|
|
178
|
+
* and the constructor. If possible, prefer using the \a Options template parameter.
|
|
151
179
|
*
|
|
152
180
|
* \param matrix the matrix to decompose
|
|
153
|
-
* \param computationOptions
|
|
154
|
-
*
|
|
155
|
-
*
|
|
181
|
+
* \param computationOptions specification for computing Thin/Full unitaries U/V
|
|
182
|
+
*
|
|
183
|
+
* \deprecated Will be removed in the next major Eigen version. Options should
|
|
184
|
+
* be specified in the \a Options template parameter.
|
|
185
|
+
*/
|
|
186
|
+
template <typename Derived>
|
|
187
|
+
EIGEN_DEPRECATED_WITH_REASON("Options should be specified using the class template parameter.")
|
|
188
|
+
BDCSVD(const MatrixBase<Derived>& matrix, unsigned int computationOptions) : m_algoswap(16), m_numIters(0) {
|
|
189
|
+
internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, matrix.rows(), matrix.cols());
|
|
190
|
+
compute_impl(matrix, computationOptions);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
~BDCSVD() {}
|
|
194
|
+
|
|
195
|
+
/** \brief Method performing the decomposition of given matrix. Computes Thin/Full unitaries U/V if specified
|
|
196
|
+
* using the \a Options template parameter or the class constructor.
|
|
156
197
|
*
|
|
157
|
-
*
|
|
158
|
-
* available with the (non - default) FullPivHouseholderQR preconditioner.
|
|
198
|
+
* \param matrix the matrix to decompose
|
|
159
199
|
*/
|
|
160
|
-
|
|
200
|
+
template <typename Derived>
|
|
201
|
+
BDCSVD& compute(const MatrixBase<Derived>& matrix) {
|
|
202
|
+
return compute_impl(matrix, m_computationOptions);
|
|
203
|
+
}
|
|
161
204
|
|
|
162
|
-
/** \brief Method performing the decomposition of given matrix
|
|
205
|
+
/** \brief Method performing the decomposition of given matrix, as specified by
|
|
206
|
+
* the `computationOptions` parameter.
|
|
163
207
|
*
|
|
164
208
|
* \param matrix the matrix to decompose
|
|
209
|
+
* \param computationOptions specify whether to compute Thin/Full unitaries U/V
|
|
165
210
|
*
|
|
166
|
-
*
|
|
211
|
+
* \deprecated Will be removed in the next major Eigen version. Options should
|
|
212
|
+
* be specified in the \a Options template parameter.
|
|
167
213
|
*/
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
template <typename Derived>
|
|
215
|
+
EIGEN_DEPRECATED_WITH_REASON("Options should be specified using the class template parameter.")
|
|
216
|
+
BDCSVD& compute(const MatrixBase<Derived>& matrix, unsigned int computationOptions) {
|
|
217
|
+
internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, matrix.rows(), matrix.cols());
|
|
218
|
+
return compute_impl(matrix, computationOptions);
|
|
171
219
|
}
|
|
172
220
|
|
|
173
|
-
void setSwitchSize(int s)
|
|
174
|
-
|
|
175
|
-
eigen_assert(s>3 && "BDCSVD the size of the algo switch has to be greater than 3");
|
|
221
|
+
void setSwitchSize(int s) {
|
|
222
|
+
eigen_assert(s >= 3 && "BDCSVD the size of the algo switch has to be at least 3.");
|
|
176
223
|
m_algoswap = s;
|
|
177
224
|
}
|
|
178
|
-
|
|
179
|
-
private:
|
|
180
|
-
|
|
225
|
+
|
|
226
|
+
private:
|
|
227
|
+
template <typename Derived>
|
|
228
|
+
BDCSVD& compute_impl(const MatrixBase<Derived>& matrix, unsigned int computationOptions);
|
|
181
229
|
void divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift);
|
|
182
230
|
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,
|
|
184
|
-
|
|
185
|
-
void
|
|
231
|
+
void computeSingVals(const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm, VectorType& singVals,
|
|
232
|
+
ArrayRef shifts, ArrayRef mus);
|
|
233
|
+
void perturbCol0(const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm, const VectorType& singVals,
|
|
234
|
+
const ArrayRef& shifts, const ArrayRef& mus, ArrayRef zhat);
|
|
235
|
+
void computeSingVecs(const ArrayRef& zhat, const ArrayRef& diag, const IndicesRef& perm, const VectorType& singVals,
|
|
236
|
+
const ArrayRef& shifts, const ArrayRef& mus, MatrixXr& U, MatrixXr& V);
|
|
186
237
|
void deflation43(Index firstCol, Index shift, Index i, Index size);
|
|
187
|
-
void deflation44(Index firstColu
|
|
238
|
+
void deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW, Index i, Index j, Index size);
|
|
188
239
|
void deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW, Index shift);
|
|
189
|
-
template<typename HouseholderU, typename HouseholderV, typename NaiveU, typename NaiveV>
|
|
190
|
-
void copyUV(const HouseholderU
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
240
|
+
template <typename HouseholderU, typename HouseholderV, typename NaiveU, typename NaiveV>
|
|
241
|
+
void copyUV(const HouseholderU& householderU, const HouseholderV& householderV, const NaiveU& naiveU,
|
|
242
|
+
const NaiveV& naivev);
|
|
243
|
+
void structured_update(Block<MatrixXr, Dynamic, Dynamic> A, const MatrixXr& B, Index n1);
|
|
244
|
+
static RealScalar secularEq(RealScalar x, const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm,
|
|
245
|
+
const ArrayRef& diagShifted, RealScalar shift);
|
|
246
|
+
template <typename SVDType>
|
|
247
|
+
void computeBaseCase(SVDType& svd, Index n, Index firstCol, Index firstRowW, Index firstColW, Index shift);
|
|
248
|
+
|
|
249
|
+
protected:
|
|
250
|
+
void allocate(Index rows, Index cols, unsigned int computationOptions);
|
|
195
251
|
MatrixXr m_naiveU, m_naiveV;
|
|
196
252
|
MatrixXr m_computed;
|
|
197
253
|
Index m_nRec;
|
|
198
254
|
ArrayXr m_workspace;
|
|
199
255
|
ArrayXi m_workspaceI;
|
|
200
256
|
int m_algoswap;
|
|
201
|
-
bool m_isTranspose, m_compU, m_compV;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
257
|
+
bool m_isTranspose, m_compU, m_compV, m_useQrDecomp;
|
|
258
|
+
JacobiSVD<MatrixType, ComputationOptions> smallSvd;
|
|
259
|
+
HouseholderQR<MatrixX> qrDecomp;
|
|
260
|
+
internal::UpperBidiagonalization<MatrixX> bid;
|
|
261
|
+
MatrixX copyWorkspace;
|
|
262
|
+
MatrixX reducedTriangle;
|
|
263
|
+
|
|
264
|
+
using Base::m_computationOptions;
|
|
207
265
|
using Base::m_computeThinU;
|
|
208
266
|
using Base::m_computeThinV;
|
|
209
|
-
using Base::m_matrixU;
|
|
210
|
-
using Base::m_matrixV;
|
|
211
267
|
using Base::m_info;
|
|
212
268
|
using Base::m_isInitialized;
|
|
269
|
+
using Base::m_matrixU;
|
|
270
|
+
using Base::m_matrixV;
|
|
213
271
|
using Base::m_nonzeroSingularValues;
|
|
272
|
+
using Base::m_singularValues;
|
|
214
273
|
|
|
215
|
-
public:
|
|
274
|
+
public:
|
|
216
275
|
int m_numIters;
|
|
217
|
-
};
|
|
218
|
-
|
|
276
|
+
}; // end class BDCSVD
|
|
219
277
|
|
|
220
278
|
// Method to allocate and initialize matrix and attributes
|
|
221
|
-
template<typename MatrixType>
|
|
222
|
-
void BDCSVD<MatrixType>::allocate(
|
|
223
|
-
|
|
224
|
-
m_isTranspose = (cols > rows);
|
|
279
|
+
template <typename MatrixType, int Options>
|
|
280
|
+
void BDCSVD<MatrixType, Options>::allocate(Index rows, Index cols, unsigned int computationOptions) {
|
|
281
|
+
if (Base::allocate(rows, cols, computationOptions)) return;
|
|
225
282
|
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
m_computed = MatrixXr::Zero(
|
|
283
|
+
if (cols < m_algoswap)
|
|
284
|
+
smallSvd.allocate(rows, cols, Options == 0 ? computationOptions : internal::get_computation_options(Options));
|
|
285
|
+
|
|
286
|
+
m_computed = MatrixXr::Zero(diagSize() + 1, diagSize());
|
|
230
287
|
m_compU = computeV();
|
|
231
288
|
m_compV = computeU();
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
289
|
+
m_isTranspose = (cols > rows);
|
|
290
|
+
if (m_isTranspose) std::swap(m_compU, m_compV);
|
|
291
|
+
|
|
292
|
+
// kMinAspectRatio is the crossover point that determines if we perform R-Bidiagonalization
|
|
293
|
+
// or bidiagonalize the input matrix directly.
|
|
294
|
+
// It is based off of LAPACK's dgesdd routine, which uses 11.0/6.0
|
|
295
|
+
// we use a larger scalar to prevent a regression for relatively square matrices.
|
|
296
|
+
constexpr Index kMinAspectRatio = 4;
|
|
297
|
+
constexpr bool disableQrDecomp = static_cast<int>(QRDecomposition) == static_cast<int>(DisableQRDecomposition);
|
|
298
|
+
m_useQrDecomp = !disableQrDecomp && ((rows / kMinAspectRatio > cols) || (cols / kMinAspectRatio > rows));
|
|
299
|
+
if (m_useQrDecomp) {
|
|
300
|
+
qrDecomp = HouseholderQR<MatrixX>((std::max)(rows, cols), (std::min)(rows, cols));
|
|
301
|
+
reducedTriangle = MatrixX(diagSize(), diagSize());
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
copyWorkspace = MatrixX(m_isTranspose ? cols : rows, m_isTranspose ? rows : cols);
|
|
305
|
+
bid = internal::UpperBidiagonalization<MatrixX>(m_useQrDecomp ? diagSize() : copyWorkspace.rows(),
|
|
306
|
+
m_useQrDecomp ? diagSize() : copyWorkspace.cols());
|
|
307
|
+
|
|
308
|
+
if (m_compU)
|
|
309
|
+
m_naiveU = MatrixXr::Zero(diagSize() + 1, diagSize() + 1);
|
|
310
|
+
else
|
|
311
|
+
m_naiveU = MatrixXr::Zero(2, diagSize() + 1);
|
|
312
|
+
|
|
313
|
+
if (m_compV) m_naiveV = MatrixXr::Zero(diagSize(), diagSize());
|
|
314
|
+
|
|
315
|
+
m_workspace.resize((diagSize() + 1) * (diagSize() + 1) * 3);
|
|
316
|
+
m_workspaceI.resize(3 * diagSize());
|
|
317
|
+
} // end allocate
|
|
318
|
+
|
|
319
|
+
template <typename MatrixType, int Options>
|
|
320
|
+
template <typename Derived>
|
|
321
|
+
BDCSVD<MatrixType, Options>& BDCSVD<MatrixType, Options>::compute_impl(const MatrixBase<Derived>& matrix,
|
|
322
|
+
unsigned int computationOptions) {
|
|
323
|
+
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived, MatrixType);
|
|
324
|
+
EIGEN_STATIC_ASSERT((std::is_same<typename Derived::Scalar, typename MatrixType::Scalar>::value),
|
|
325
|
+
Input matrix must have the same Scalar type as the BDCSVD object.);
|
|
326
|
+
|
|
247
327
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
248
|
-
std::cout << "\n\n\n
|
|
328
|
+
std::cout << "\n\n\n================================================================================================="
|
|
329
|
+
"=====================\n\n\n";
|
|
249
330
|
#endif
|
|
250
|
-
allocate(matrix.rows(), matrix.cols(), computationOptions);
|
|
251
331
|
using std::abs;
|
|
252
332
|
|
|
333
|
+
allocate(matrix.rows(), matrix.cols(), computationOptions);
|
|
334
|
+
|
|
253
335
|
const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
|
|
254
|
-
|
|
336
|
+
|
|
255
337
|
//**** step -1 - If the problem is too small, directly falls back to JacobiSVD and return
|
|
256
|
-
if(matrix.cols() < m_algoswap)
|
|
257
|
-
|
|
258
|
-
// FIXME this line involves temporaries
|
|
259
|
-
JacobiSVD<MatrixType> jsvd(matrix,computationOptions);
|
|
338
|
+
if (matrix.cols() < m_algoswap) {
|
|
339
|
+
smallSvd.compute(matrix);
|
|
260
340
|
m_isInitialized = true;
|
|
261
|
-
m_info =
|
|
341
|
+
m_info = smallSvd.info();
|
|
262
342
|
if (m_info == Success || m_info == NoConvergence) {
|
|
263
|
-
if(computeU()) m_matrixU =
|
|
264
|
-
if(computeV()) m_matrixV =
|
|
265
|
-
m_singularValues =
|
|
266
|
-
m_nonzeroSingularValues =
|
|
343
|
+
if (computeU()) m_matrixU = smallSvd.matrixU();
|
|
344
|
+
if (computeV()) m_matrixV = smallSvd.matrixV();
|
|
345
|
+
m_singularValues = smallSvd.singularValues();
|
|
346
|
+
m_nonzeroSingularValues = smallSvd.nonzeroSingularValues();
|
|
267
347
|
}
|
|
268
348
|
return *this;
|
|
269
349
|
}
|
|
270
|
-
|
|
350
|
+
|
|
271
351
|
//**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows
|
|
272
352
|
RealScalar scale = matrix.cwiseAbs().template maxCoeff<PropagateNaN>();
|
|
273
353
|
if (!(numext::isfinite)(scale)) {
|
|
@@ -276,312 +356,325 @@ BDCSVD<MatrixType>& BDCSVD<MatrixType>::compute(const MatrixType& matrix, unsign
|
|
|
276
356
|
return *this;
|
|
277
357
|
}
|
|
278
358
|
|
|
279
|
-
if(scale
|
|
280
|
-
|
|
281
|
-
if (m_isTranspose)
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
359
|
+
if (numext::is_exactly_zero(scale)) scale = Literal(1);
|
|
360
|
+
|
|
361
|
+
if (m_isTranspose)
|
|
362
|
+
copyWorkspace = matrix.adjoint() / scale;
|
|
363
|
+
else
|
|
364
|
+
copyWorkspace = matrix / scale;
|
|
365
|
+
|
|
366
|
+
//**** step 1 - Bidiagonalization.
|
|
367
|
+
// If the problem is sufficiently rectangular, we perform R-Bidiagonalization: compute A = Q(R/0)
|
|
368
|
+
// and then bidiagonalize R. Otherwise, if the problem is relatively square, we
|
|
369
|
+
// bidiagonalize the input matrix directly.
|
|
370
|
+
if (m_useQrDecomp) {
|
|
371
|
+
qrDecomp.compute(copyWorkspace);
|
|
372
|
+
reducedTriangle = qrDecomp.matrixQR().topRows(diagSize());
|
|
373
|
+
reducedTriangle.template triangularView<StrictlyLower>().setZero();
|
|
374
|
+
bid.compute(reducedTriangle);
|
|
375
|
+
} else {
|
|
376
|
+
bid.compute(copyWorkspace);
|
|
377
|
+
}
|
|
287
378
|
|
|
288
379
|
//**** step 2 - Divide & Conquer
|
|
289
380
|
m_naiveU.setZero();
|
|
290
381
|
m_naiveV.setZero();
|
|
291
382
|
// FIXME this line involves a temporary matrix
|
|
292
|
-
m_computed.topRows(
|
|
383
|
+
m_computed.topRows(diagSize()) = bid.bidiagonal().toDenseMatrix().transpose();
|
|
293
384
|
m_computed.template bottomRows<1>().setZero();
|
|
294
|
-
divide(0,
|
|
385
|
+
divide(0, diagSize() - 1, 0, 0, 0);
|
|
295
386
|
if (m_info != Success && m_info != NoConvergence) {
|
|
296
387
|
m_isInitialized = true;
|
|
297
388
|
return *this;
|
|
298
389
|
}
|
|
299
|
-
|
|
390
|
+
|
|
300
391
|
//**** step 3 - Copy singular values and vectors
|
|
301
|
-
for (int i=0; i<
|
|
302
|
-
{
|
|
392
|
+
for (int i = 0; i < diagSize(); i++) {
|
|
303
393
|
RealScalar a = abs(m_computed.coeff(i, i));
|
|
304
394
|
m_singularValues.coeffRef(i) = a * scale;
|
|
305
|
-
if (a<considerZero)
|
|
306
|
-
{
|
|
395
|
+
if (a < considerZero) {
|
|
307
396
|
m_nonzeroSingularValues = i;
|
|
308
|
-
m_singularValues.tail(
|
|
397
|
+
m_singularValues.tail(diagSize() - i - 1).setZero();
|
|
309
398
|
break;
|
|
310
|
-
}
|
|
311
|
-
else if (i == m_diagSize - 1)
|
|
312
|
-
{
|
|
399
|
+
} else if (i == diagSize() - 1) {
|
|
313
400
|
m_nonzeroSingularValues = i + 1;
|
|
314
401
|
break;
|
|
315
402
|
}
|
|
316
403
|
}
|
|
317
404
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
405
|
+
//**** step 4 - Finalize unitaries U and V
|
|
406
|
+
if (m_isTranspose)
|
|
407
|
+
copyUV(bid.householderV(), bid.householderU(), m_naiveV, m_naiveU);
|
|
408
|
+
else
|
|
409
|
+
copyUV(bid.householderU(), bid.householderV(), m_naiveU, m_naiveV);
|
|
410
|
+
|
|
411
|
+
if (m_useQrDecomp) {
|
|
412
|
+
if (m_isTranspose && computeV())
|
|
413
|
+
m_matrixV.applyOnTheLeft(qrDecomp.householderQ());
|
|
414
|
+
else if (!m_isTranspose && computeU())
|
|
415
|
+
m_matrixU.applyOnTheLeft(qrDecomp.householderQ());
|
|
416
|
+
}
|
|
324
417
|
|
|
325
418
|
m_isInitialized = true;
|
|
326
419
|
return *this;
|
|
327
|
-
}// end compute
|
|
328
|
-
|
|
420
|
+
} // end compute
|
|
329
421
|
|
|
330
|
-
template<typename MatrixType>
|
|
331
|
-
template<typename HouseholderU, typename HouseholderV, typename NaiveU, typename NaiveV>
|
|
332
|
-
void BDCSVD<MatrixType>::copyUV(const HouseholderU
|
|
333
|
-
{
|
|
422
|
+
template <typename MatrixType, int Options>
|
|
423
|
+
template <typename HouseholderU, typename HouseholderV, typename NaiveU, typename NaiveV>
|
|
424
|
+
void BDCSVD<MatrixType, Options>::copyUV(const HouseholderU& householderU, const HouseholderV& householderV,
|
|
425
|
+
const NaiveU& naiveU, const NaiveV& naiveV) {
|
|
334
426
|
// Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa
|
|
335
|
-
if (computeU())
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
m_matrixU
|
|
339
|
-
|
|
340
|
-
|
|
427
|
+
if (computeU()) {
|
|
428
|
+
Index Ucols = m_computeThinU ? diagSize() : rows();
|
|
429
|
+
m_matrixU = MatrixX::Identity(rows(), Ucols);
|
|
430
|
+
m_matrixU.topLeftCorner(diagSize(), diagSize()) =
|
|
431
|
+
naiveV.template cast<Scalar>().topLeftCorner(diagSize(), diagSize());
|
|
432
|
+
// FIXME the following conditionals involve temporary buffers
|
|
433
|
+
if (m_useQrDecomp)
|
|
434
|
+
m_matrixU.topLeftCorner(householderU.cols(), diagSize()).applyOnTheLeft(householderU);
|
|
435
|
+
else
|
|
436
|
+
m_matrixU.applyOnTheLeft(householderU);
|
|
341
437
|
}
|
|
342
|
-
if (computeV())
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
m_matrixV
|
|
346
|
-
|
|
347
|
-
|
|
438
|
+
if (computeV()) {
|
|
439
|
+
Index Vcols = m_computeThinV ? diagSize() : cols();
|
|
440
|
+
m_matrixV = MatrixX::Identity(cols(), Vcols);
|
|
441
|
+
m_matrixV.topLeftCorner(diagSize(), diagSize()) =
|
|
442
|
+
naiveU.template cast<Scalar>().topLeftCorner(diagSize(), diagSize());
|
|
443
|
+
// FIXME the following conditionals involve temporary buffers
|
|
444
|
+
if (m_useQrDecomp)
|
|
445
|
+
m_matrixV.topLeftCorner(householderV.cols(), diagSize()).applyOnTheLeft(householderV);
|
|
446
|
+
else
|
|
447
|
+
m_matrixV.applyOnTheLeft(householderV);
|
|
348
448
|
}
|
|
349
449
|
}
|
|
350
450
|
|
|
351
451
|
/** \internal
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
template<typename MatrixType>
|
|
360
|
-
void BDCSVD<MatrixType>::structured_update(Block<MatrixXr,Dynamic,Dynamic> A, const MatrixXr
|
|
361
|
-
{
|
|
452
|
+
* Performs A = A * B exploiting the special structure of the matrix A. Splitting A as:
|
|
453
|
+
* A = [A1]
|
|
454
|
+
* [A2]
|
|
455
|
+
* such that A1.rows()==n1, then we assume that at least half of the columns of A1 and A2 are zeros.
|
|
456
|
+
* We can thus pack them prior to the the matrix product. However, this is only worth the effort if the matrix is large
|
|
457
|
+
* enough.
|
|
458
|
+
*/
|
|
459
|
+
template <typename MatrixType, int Options>
|
|
460
|
+
void BDCSVD<MatrixType, Options>::structured_update(Block<MatrixXr, Dynamic, Dynamic> A, const MatrixXr& B, Index n1) {
|
|
362
461
|
Index n = A.rows();
|
|
363
|
-
if(n>100)
|
|
364
|
-
{
|
|
462
|
+
if (n > 100) {
|
|
365
463
|
// If the matrices are large enough, let's exploit the sparse structure of A by
|
|
366
464
|
// splitting it in half (wrt n1), and packing the non-zero columns.
|
|
367
465
|
Index n2 = n - n1;
|
|
368
|
-
Map<MatrixXr> A1(m_workspace.data()
|
|
369
|
-
Map<MatrixXr> A2(m_workspace.data()+ n1*n, n2, n);
|
|
370
|
-
Map<MatrixXr> B1(m_workspace.data()+
|
|
371
|
-
Map<MatrixXr> B2(m_workspace.data()+2*n*n, n,
|
|
372
|
-
Index k1=0, k2=0;
|
|
373
|
-
for(Index j=0; j<n; ++j)
|
|
374
|
-
|
|
375
|
-
if( (A.col(j).head(n1).array()!=Literal(0)).any() )
|
|
376
|
-
{
|
|
466
|
+
Map<MatrixXr> A1(m_workspace.data(), n1, n);
|
|
467
|
+
Map<MatrixXr> A2(m_workspace.data() + n1 * n, n2, n);
|
|
468
|
+
Map<MatrixXr> B1(m_workspace.data() + n * n, n, n);
|
|
469
|
+
Map<MatrixXr> B2(m_workspace.data() + 2 * n * n, n, n);
|
|
470
|
+
Index k1 = 0, k2 = 0;
|
|
471
|
+
for (Index j = 0; j < n; ++j) {
|
|
472
|
+
if ((A.col(j).head(n1).array() != Literal(0)).any()) {
|
|
377
473
|
A1.col(k1) = A.col(j).head(n1);
|
|
378
474
|
B1.row(k1) = B.row(j);
|
|
379
475
|
++k1;
|
|
380
476
|
}
|
|
381
|
-
if
|
|
382
|
-
{
|
|
477
|
+
if ((A.col(j).tail(n2).array() != Literal(0)).any()) {
|
|
383
478
|
A2.col(k2) = A.col(j).tail(n2);
|
|
384
479
|
B2.row(k2) = B.row(j);
|
|
385
480
|
++k2;
|
|
386
481
|
}
|
|
387
482
|
}
|
|
388
|
-
|
|
389
|
-
A.topRows(n1).noalias()
|
|
483
|
+
|
|
484
|
+
A.topRows(n1).noalias() = A1.leftCols(k1) * B1.topRows(k1);
|
|
390
485
|
A.bottomRows(n2).noalias() = A2.leftCols(k2) * B2.topRows(k2);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
Map<MatrixXr,Aligned> tmp(m_workspace.data(),n,n);
|
|
395
|
-
tmp.noalias() = A*B;
|
|
486
|
+
} else {
|
|
487
|
+
Map<MatrixXr, Aligned> tmp(m_workspace.data(), n, n);
|
|
488
|
+
tmp.noalias() = A * B;
|
|
396
489
|
A = tmp;
|
|
397
490
|
}
|
|
398
491
|
}
|
|
399
492
|
|
|
400
|
-
|
|
401
|
-
|
|
493
|
+
template <typename MatrixType, int Options>
|
|
494
|
+
template <typename SVDType>
|
|
495
|
+
void BDCSVD<MatrixType, Options>::computeBaseCase(SVDType& svd, Index n, Index firstCol, Index firstRowW,
|
|
496
|
+
Index firstColW, Index shift) {
|
|
497
|
+
svd.compute(m_computed.block(firstCol, firstCol, n + 1, n));
|
|
498
|
+
m_info = svd.info();
|
|
499
|
+
if (m_info != Success && m_info != NoConvergence) return;
|
|
500
|
+
if (m_compU)
|
|
501
|
+
m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = svd.matrixU();
|
|
502
|
+
else {
|
|
503
|
+
m_naiveU.row(0).segment(firstCol, n + 1).real() = svd.matrixU().row(0);
|
|
504
|
+
m_naiveU.row(1).segment(firstCol, n + 1).real() = svd.matrixU().row(n);
|
|
505
|
+
}
|
|
506
|
+
if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = svd.matrixV();
|
|
507
|
+
m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero();
|
|
508
|
+
m_computed.diagonal().segment(firstCol + shift, n) = svd.singularValues().head(n);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// The divide algorithm is done "in place", we are always working on subsets of the same matrix. The divide methods
|
|
512
|
+
// takes as argument the place of the submatrix we are currently working on.
|
|
402
513
|
|
|
403
514
|
//@param firstCol : The Index of the first column of the submatrix of m_computed and for m_naiveU;
|
|
404
|
-
//@param lastCol : The Index of the last column of the submatrix of m_computed and for m_naiveU;
|
|
515
|
+
//@param lastCol : The Index of the last column of the submatrix of m_computed and for m_naiveU;
|
|
405
516
|
// lastCol + 1 - firstCol is the size of the submatrix.
|
|
406
|
-
//@param firstRowW : The Index of the first row of the matrix W that we are to change. (see the reference paper section
|
|
407
|
-
|
|
408
|
-
//@param
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
517
|
+
//@param firstRowW : The Index of the first row of the matrix W that we are to change. (see the reference paper section
|
|
518
|
+
// 1 for more information on W)
|
|
519
|
+
//@param firstColW : Same as firstRowW with the column.
|
|
520
|
+
//@param shift : Each time one takes the left submatrix, one must add 1 to the shift. Why? Because! We actually want the
|
|
521
|
+
// last column of the U submatrix
|
|
522
|
+
// to become the first column (*coeff) and to shift all the other columns to the right. There are more details on the
|
|
523
|
+
// reference paper.
|
|
524
|
+
template <typename MatrixType, int Options>
|
|
525
|
+
void BDCSVD<MatrixType, Options>::divide(Index firstCol, Index lastCol, Index firstRowW, Index firstColW, Index shift) {
|
|
413
526
|
// requires rows = cols + 1;
|
|
527
|
+
using std::abs;
|
|
414
528
|
using std::pow;
|
|
415
529
|
using std::sqrt;
|
|
416
|
-
using std::abs;
|
|
417
530
|
const Index n = lastCol - firstCol + 1;
|
|
418
|
-
const Index k = n/2;
|
|
531
|
+
const Index k = n / 2;
|
|
419
532
|
const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
|
|
420
533
|
RealScalar alphaK;
|
|
421
|
-
RealScalar betaK;
|
|
422
|
-
RealScalar r0;
|
|
534
|
+
RealScalar betaK;
|
|
535
|
+
RealScalar r0;
|
|
423
536
|
RealScalar lambda, phi, c0, s0;
|
|
424
537
|
VectorType l, f;
|
|
425
|
-
// We use the other algorithm which is more efficient for small
|
|
538
|
+
// We use the other algorithm which is more efficient for small
|
|
426
539
|
// matrices.
|
|
427
|
-
if (n < m_algoswap)
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
else
|
|
436
|
-
{
|
|
437
|
-
m_naiveU.row(0).segment(firstCol, n + 1).real() = b.matrixU().row(0);
|
|
438
|
-
m_naiveU.row(1).segment(firstCol, n + 1).real() = b.matrixU().row(n);
|
|
540
|
+
if (n < m_algoswap) {
|
|
541
|
+
// FIXME this block involves temporaries
|
|
542
|
+
if (m_compV) {
|
|
543
|
+
JacobiSVD<MatrixXr, ComputeFullU | ComputeFullV> baseSvd;
|
|
544
|
+
computeBaseCase(baseSvd, n, firstCol, firstRowW, firstColW, shift);
|
|
545
|
+
} else {
|
|
546
|
+
JacobiSVD<MatrixXr, ComputeFullU> baseSvd;
|
|
547
|
+
computeBaseCase(baseSvd, n, firstCol, firstRowW, firstColW, shift);
|
|
439
548
|
}
|
|
440
|
-
if (m_compV) m_naiveV.block(firstRowW, firstColW, n, n).real() = b.matrixV();
|
|
441
|
-
m_computed.block(firstCol + shift, firstCol + shift, n + 1, n).setZero();
|
|
442
|
-
m_computed.diagonal().segment(firstCol + shift, n) = b.singularValues().head(n);
|
|
443
549
|
return;
|
|
444
550
|
}
|
|
445
551
|
// We use the divide and conquer algorithm
|
|
446
|
-
alphaK =
|
|
552
|
+
alphaK = m_computed(firstCol + k, firstCol + k);
|
|
447
553
|
betaK = m_computed(firstCol + k + 1, firstCol + k);
|
|
448
554
|
// The divide must be done in that order in order to have good results. Divide change the data inside the submatrices
|
|
449
|
-
// and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the
|
|
450
|
-
// right submatrix before the left one.
|
|
555
|
+
// and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the
|
|
556
|
+
// right submatrix before the left one.
|
|
451
557
|
divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift);
|
|
452
558
|
if (m_info != Success && m_info != NoConvergence) return;
|
|
453
559
|
divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1);
|
|
454
560
|
if (m_info != Success && m_info != NoConvergence) return;
|
|
455
561
|
|
|
456
|
-
if (m_compU)
|
|
457
|
-
{
|
|
562
|
+
if (m_compU) {
|
|
458
563
|
lambda = m_naiveU(firstCol + k, firstCol + k);
|
|
459
564
|
phi = m_naiveU(firstCol + k + 1, lastCol + 1);
|
|
460
|
-
}
|
|
461
|
-
else
|
|
462
|
-
{
|
|
565
|
+
} else {
|
|
463
566
|
lambda = m_naiveU(1, firstCol + k);
|
|
464
567
|
phi = m_naiveU(0, lastCol + 1);
|
|
465
568
|
}
|
|
466
569
|
r0 = sqrt((abs(alphaK * lambda) * abs(alphaK * lambda)) + abs(betaK * phi) * abs(betaK * phi));
|
|
467
|
-
if (m_compU)
|
|
468
|
-
{
|
|
570
|
+
if (m_compU) {
|
|
469
571
|
l = m_naiveU.row(firstCol + k).segment(firstCol, k);
|
|
470
572
|
f = m_naiveU.row(firstCol + k + 1).segment(firstCol + k + 1, n - k - 1);
|
|
471
|
-
}
|
|
472
|
-
else
|
|
473
|
-
{
|
|
573
|
+
} else {
|
|
474
574
|
l = m_naiveU.row(1).segment(firstCol, k);
|
|
475
575
|
f = m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1);
|
|
476
576
|
}
|
|
477
|
-
if (m_compV) m_naiveV(firstRowW+k, firstColW) = Literal(1);
|
|
478
|
-
if (r0<considerZero)
|
|
479
|
-
{
|
|
577
|
+
if (m_compV) m_naiveV(firstRowW + k, firstColW) = Literal(1);
|
|
578
|
+
if (r0 < considerZero) {
|
|
480
579
|
c0 = Literal(1);
|
|
481
580
|
s0 = Literal(0);
|
|
482
|
-
}
|
|
483
|
-
else
|
|
484
|
-
{
|
|
581
|
+
} else {
|
|
485
582
|
c0 = alphaK * lambda / r0;
|
|
486
583
|
s0 = betaK * phi / r0;
|
|
487
584
|
}
|
|
488
|
-
|
|
585
|
+
|
|
489
586
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
587
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
588
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
589
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
493
590
|
#endif
|
|
494
|
-
|
|
495
|
-
if (m_compU)
|
|
496
|
-
|
|
497
|
-
MatrixXr q1 (m_naiveU.col(firstCol + k).segment(firstCol, k + 1));
|
|
591
|
+
|
|
592
|
+
if (m_compU) {
|
|
593
|
+
MatrixXr q1(m_naiveU.col(firstCol + k).segment(firstCol, k + 1));
|
|
498
594
|
// we shiftW Q1 to the right
|
|
499
|
-
for (Index i = firstCol + k - 1; i >= firstCol; i--)
|
|
595
|
+
for (Index i = firstCol + k - 1; i >= firstCol; i--)
|
|
500
596
|
m_naiveU.col(i + 1).segment(firstCol, k + 1) = m_naiveU.col(i).segment(firstCol, k + 1);
|
|
501
597
|
// we shift q1 at the left with a factor c0
|
|
502
|
-
m_naiveU.col(firstCol).segment(
|
|
598
|
+
m_naiveU.col(firstCol).segment(firstCol, k + 1) = (q1 * c0);
|
|
503
599
|
// last column = q1 * - s0
|
|
504
|
-
m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * (
|
|
600
|
+
m_naiveU.col(lastCol + 1).segment(firstCol, k + 1) = (q1 * (-s0));
|
|
505
601
|
// first column = q2 * s0
|
|
506
|
-
m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) =
|
|
602
|
+
m_naiveU.col(firstCol).segment(firstCol + k + 1, n - k) =
|
|
603
|
+
m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) * s0;
|
|
507
604
|
// q2 *= c0
|
|
508
605
|
m_naiveU.col(lastCol + 1).segment(firstCol + k + 1, n - k) *= c0;
|
|
509
|
-
}
|
|
510
|
-
else
|
|
511
|
-
{
|
|
606
|
+
} else {
|
|
512
607
|
RealScalar q1 = m_naiveU(0, firstCol + k);
|
|
513
608
|
// we shift Q1 to the right
|
|
514
|
-
for (Index i = firstCol + k - 1; i >= firstCol; i--)
|
|
515
|
-
m_naiveU(0, i + 1) = m_naiveU(0, i);
|
|
609
|
+
for (Index i = firstCol + k - 1; i >= firstCol; i--) m_naiveU(0, i + 1) = m_naiveU(0, i);
|
|
516
610
|
// we shift q1 at the left with a factor c0
|
|
517
611
|
m_naiveU(0, firstCol) = (q1 * c0);
|
|
518
612
|
// last column = q1 * - s0
|
|
519
|
-
m_naiveU(0, lastCol + 1) = (q1 * (
|
|
613
|
+
m_naiveU(0, lastCol + 1) = (q1 * (-s0));
|
|
520
614
|
// first column = q2 * s0
|
|
521
|
-
m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) *s0;
|
|
615
|
+
m_naiveU(1, firstCol) = m_naiveU(1, lastCol + 1) * s0;
|
|
522
616
|
// q2 *= c0
|
|
523
617
|
m_naiveU(1, lastCol + 1) *= c0;
|
|
524
618
|
m_naiveU.row(1).segment(firstCol + 1, k).setZero();
|
|
525
619
|
m_naiveU.row(0).segment(firstCol + k + 1, n - k - 1).setZero();
|
|
526
620
|
}
|
|
527
|
-
|
|
621
|
+
|
|
528
622
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
623
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
624
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
625
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
532
626
|
#endif
|
|
533
|
-
|
|
627
|
+
|
|
534
628
|
m_computed(firstCol + shift, firstCol + shift) = r0;
|
|
535
629
|
m_computed.col(firstCol + shift).segment(firstCol + shift + 1, k) = alphaK * l.transpose().real();
|
|
536
630
|
m_computed.col(firstCol + shift).segment(firstCol + shift + k + 1, n - k - 1) = betaK * f.transpose().real();
|
|
537
631
|
|
|
538
632
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
539
|
-
ArrayXr tmp1 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues();
|
|
633
|
+
ArrayXr tmp1 = (m_computed.block(firstCol + shift, firstCol + shift, n, n)).jacobiSvd().singularValues();
|
|
540
634
|
#endif
|
|
541
635
|
// Second part: try to deflate singular values in combined matrix
|
|
542
636
|
deflation(firstCol, lastCol, k, firstRowW, firstColW, shift);
|
|
543
637
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
544
|
-
ArrayXr tmp2 = (m_computed.block(firstCol+shift, firstCol+shift, n, n)).jacobiSvd().singularValues();
|
|
638
|
+
ArrayXr tmp2 = (m_computed.block(firstCol + shift, firstCol + shift, n, n)).jacobiSvd().singularValues();
|
|
545
639
|
std::cout << "\n\nj1 = " << tmp1.transpose().format(bdcsvdfmt) << "\n";
|
|
546
640
|
std::cout << "j2 = " << tmp2.transpose().format(bdcsvdfmt) << "\n\n";
|
|
547
|
-
std::cout << "err: " << ((tmp1-tmp2).abs()>1e-12*tmp2.abs()).transpose() << "\n";
|
|
641
|
+
std::cout << "err: " << ((tmp1 - tmp2).abs() > 1e-12 * tmp2.abs()).transpose() << "\n";
|
|
548
642
|
static int count = 0;
|
|
549
643
|
std::cout << "# " << ++count << "\n\n";
|
|
550
|
-
|
|
551
|
-
//
|
|
552
|
-
//
|
|
644
|
+
eigen_internal_assert((tmp1 - tmp2).matrix().norm() < 1e-14 * tmp2.matrix().norm());
|
|
645
|
+
// eigen_internal_assert(count<681);
|
|
646
|
+
// eigen_internal_assert(((tmp1-tmp2).abs()<1e-13*tmp2.abs()).all());
|
|
553
647
|
#endif
|
|
554
|
-
|
|
648
|
+
|
|
555
649
|
// Third part: compute SVD of combined matrix
|
|
556
650
|
MatrixXr UofSVD, VofSVD;
|
|
557
651
|
VectorType singVals;
|
|
558
652
|
computeSVDofM(firstCol + shift, n, UofSVD, singVals, VofSVD);
|
|
559
|
-
|
|
653
|
+
|
|
560
654
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
561
|
-
|
|
562
|
-
|
|
655
|
+
eigen_internal_assert(UofSVD.allFinite());
|
|
656
|
+
eigen_internal_assert(VofSVD.allFinite());
|
|
563
657
|
#endif
|
|
564
|
-
|
|
658
|
+
|
|
565
659
|
if (m_compU)
|
|
566
|
-
structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n+2)/2);
|
|
567
|
-
else
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
tmp.noalias() = m_naiveU.middleCols(firstCol, n+1) * UofSVD;
|
|
660
|
+
structured_update(m_naiveU.block(firstCol, firstCol, n + 1, n + 1), UofSVD, (n + 2) / 2);
|
|
661
|
+
else {
|
|
662
|
+
Map<Matrix<RealScalar, 2, Dynamic>, Aligned> tmp(m_workspace.data(), 2, n + 1);
|
|
663
|
+
tmp.noalias() = m_naiveU.middleCols(firstCol, n + 1) * UofSVD;
|
|
571
664
|
m_naiveU.middleCols(firstCol, n + 1) = tmp;
|
|
572
665
|
}
|
|
573
|
-
|
|
574
|
-
if (m_compV)
|
|
575
|
-
|
|
666
|
+
|
|
667
|
+
if (m_compV) structured_update(m_naiveV.block(firstRowW, firstColW, n, n), VofSVD, (n + 1) / 2);
|
|
668
|
+
|
|
576
669
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
670
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
671
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
672
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
580
673
|
#endif
|
|
581
|
-
|
|
674
|
+
|
|
582
675
|
m_computed.block(firstCol + shift, firstCol + shift, n, n).setZero();
|
|
583
676
|
m_computed.block(firstCol + shift, firstCol + shift, n, n).diagonal() = singVals;
|
|
584
|
-
}// end divide
|
|
677
|
+
} // end divide
|
|
585
678
|
|
|
586
679
|
// Compute SVD of m_computed.block(firstCol, firstCol, n + 1, n); this block only has non-zeros in
|
|
587
680
|
// the first column and on the diagonal and has undergone deflation, so diagonal is in increasing
|
|
@@ -590,470 +683,475 @@ void BDCSVD<MatrixType>::divide(Eigen::Index firstCol, Eigen::Index lastCol, Eig
|
|
|
590
683
|
//
|
|
591
684
|
// TODO Opportunities for optimization: better root finding algo, better stopping criterion, better
|
|
592
685
|
// handling of round-off errors, be consistent in ordering
|
|
593
|
-
// For instance, to solve the secular equation using FMM, see
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
686
|
+
// For instance, to solve the secular equation using FMM, see
|
|
687
|
+
// http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf
|
|
688
|
+
template <typename MatrixType, int Options>
|
|
689
|
+
void BDCSVD<MatrixType, Options>::computeSVDofM(Index firstCol, Index n, MatrixXr& U, VectorType& singVals,
|
|
690
|
+
MatrixXr& V) {
|
|
597
691
|
const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
|
|
598
692
|
using std::abs;
|
|
599
693
|
ArrayRef col0 = m_computed.col(firstCol).segment(firstCol, n);
|
|
600
|
-
m_workspace.head(n) =
|
|
694
|
+
m_workspace.head(n) = m_computed.block(firstCol, firstCol, n, n).diagonal();
|
|
601
695
|
ArrayRef diag = m_workspace.head(n);
|
|
602
696
|
diag(0) = Literal(0);
|
|
603
697
|
|
|
604
698
|
// Allocate space for singular values and vectors
|
|
605
699
|
singVals.resize(n);
|
|
606
|
-
U.resize(n+1, n+1);
|
|
700
|
+
U.resize(n + 1, n + 1);
|
|
607
701
|
if (m_compV) V.resize(n, n);
|
|
608
702
|
|
|
609
703
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
610
|
-
if (col0.hasNaN() || diag.hasNaN())
|
|
611
|
-
std::cout << "\n\nHAS NAN\n\n";
|
|
704
|
+
if (col0.hasNaN() || diag.hasNaN()) std::cout << "\n\nHAS NAN\n\n";
|
|
612
705
|
#endif
|
|
613
|
-
|
|
706
|
+
|
|
614
707
|
// Many singular values might have been deflated, the zero ones have been moved to the end,
|
|
615
708
|
// but others are interleaved and we must ignore them at this stage.
|
|
616
709
|
// To this end, let's compute a permutation skipping them:
|
|
617
710
|
Index actual_n = n;
|
|
618
|
-
while(actual_n>1 && diag(actual_n-1)
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
Map<
|
|
626
|
-
|
|
627
|
-
Map<ArrayXr>
|
|
711
|
+
while (actual_n > 1 && numext::is_exactly_zero(diag(actual_n - 1))) {
|
|
712
|
+
--actual_n;
|
|
713
|
+
eigen_internal_assert(numext::is_exactly_zero(col0(actual_n)));
|
|
714
|
+
}
|
|
715
|
+
Index m = 0; // size of the deflated problem
|
|
716
|
+
for (Index k = 0; k < actual_n; ++k)
|
|
717
|
+
if (abs(col0(k)) > considerZero) m_workspaceI(m++) = k;
|
|
718
|
+
Map<ArrayXi> perm(m_workspaceI.data(), m);
|
|
719
|
+
|
|
720
|
+
Map<ArrayXr> shifts(m_workspace.data() + 1 * n, n);
|
|
721
|
+
Map<ArrayXr> mus(m_workspace.data() + 2 * n, n);
|
|
722
|
+
Map<ArrayXr> zhat(m_workspace.data() + 3 * n, n);
|
|
628
723
|
|
|
629
724
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
630
725
|
std::cout << "computeSVDofM using:\n";
|
|
631
726
|
std::cout << " z: " << col0.transpose() << "\n";
|
|
632
727
|
std::cout << " d: " << diag.transpose() << "\n";
|
|
633
728
|
#endif
|
|
634
|
-
|
|
729
|
+
|
|
635
730
|
// Compute singVals, shifts, and mus
|
|
636
731
|
computeSingVals(col0, diag, perm, singVals, shifts, mus);
|
|
637
|
-
|
|
732
|
+
|
|
638
733
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
639
|
-
std::cout << " j: "
|
|
734
|
+
std::cout << " j: "
|
|
735
|
+
<< (m_computed.block(firstCol, firstCol, n, n)).jacobiSvd().singularValues().transpose().reverse()
|
|
736
|
+
<< "\n\n";
|
|
640
737
|
std::cout << " sing-val: " << singVals.transpose() << "\n";
|
|
641
738
|
std::cout << " mu: " << mus.transpose() << "\n";
|
|
642
739
|
std::cout << " shift: " << shifts.transpose() << "\n";
|
|
643
|
-
|
|
740
|
+
|
|
644
741
|
{
|
|
645
742
|
std::cout << "\n\n mus: " << mus.head(actual_n).transpose() << "\n\n";
|
|
646
|
-
std::cout << " check1 (expect0) : "
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
743
|
+
std::cout << " check1 (expect0) : "
|
|
744
|
+
<< ((singVals.array() - (shifts + mus)) / singVals.array()).head(actual_n).transpose() << "\n\n";
|
|
745
|
+
eigen_internal_assert((((singVals.array() - (shifts + mus)) / singVals.array()).head(actual_n) >= 0).all());
|
|
746
|
+
std::cout << " check2 (>0) : " << ((singVals.array() - diag) / singVals.array()).head(actual_n).transpose()
|
|
747
|
+
<< "\n\n";
|
|
748
|
+
eigen_internal_assert((((singVals.array() - diag) / singVals.array()).head(actual_n) >= 0).all());
|
|
650
749
|
}
|
|
651
750
|
#endif
|
|
652
|
-
|
|
751
|
+
|
|
653
752
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
753
|
+
eigen_internal_assert(singVals.allFinite());
|
|
754
|
+
eigen_internal_assert(mus.allFinite());
|
|
755
|
+
eigen_internal_assert(shifts.allFinite());
|
|
657
756
|
#endif
|
|
658
|
-
|
|
757
|
+
|
|
659
758
|
// Compute zhat
|
|
660
759
|
perturbCol0(col0, diag, perm, singVals, shifts, mus, zhat);
|
|
661
|
-
#ifdef
|
|
760
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
662
761
|
std::cout << " zhat: " << zhat.transpose() << "\n";
|
|
663
762
|
#endif
|
|
664
|
-
|
|
763
|
+
|
|
665
764
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
666
|
-
|
|
765
|
+
eigen_internal_assert(zhat.allFinite());
|
|
667
766
|
#endif
|
|
668
|
-
|
|
767
|
+
|
|
669
768
|
computeSingVecs(zhat, diag, perm, singVals, shifts, mus, U, V);
|
|
670
|
-
|
|
671
|
-
#ifdef
|
|
672
|
-
std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() << "\n";
|
|
673
|
-
std::cout << "V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() << "\n";
|
|
769
|
+
|
|
770
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
771
|
+
std::cout << "U^T U: " << (U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(), U.cols()))).norm() << "\n";
|
|
772
|
+
std::cout << "V^T V: " << (V.transpose() * V - MatrixXr(MatrixXr::Identity(V.cols(), V.cols()))).norm() << "\n";
|
|
674
773
|
#endif
|
|
675
|
-
|
|
774
|
+
|
|
676
775
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
//
|
|
683
|
-
//
|
|
776
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
777
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
778
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
779
|
+
eigen_internal_assert(U.allFinite());
|
|
780
|
+
eigen_internal_assert(V.allFinite());
|
|
781
|
+
// eigen_internal_assert((U.transpose() * U - MatrixXr(MatrixXr::Identity(U.cols(),U.cols()))).norm() <
|
|
782
|
+
// 100*NumTraits<RealScalar>::epsilon() * n); eigen_internal_assert((V.transpose() * V -
|
|
783
|
+
// MatrixXr(MatrixXr::Identity(V.cols(),V.cols()))).norm() < 100*NumTraits<RealScalar>::epsilon() * n);
|
|
684
784
|
#endif
|
|
685
|
-
|
|
785
|
+
|
|
686
786
|
// Because of deflation, the singular values might not be completely sorted.
|
|
687
787
|
// Fortunately, reordering them is a O(n) problem
|
|
688
|
-
for(Index i=0; i<actual_n-1; ++i)
|
|
689
|
-
|
|
690
|
-
if(singVals(i)>singVals(i+1))
|
|
691
|
-
{
|
|
788
|
+
for (Index i = 0; i < actual_n - 1; ++i) {
|
|
789
|
+
if (singVals(i) > singVals(i + 1)) {
|
|
692
790
|
using std::swap;
|
|
693
|
-
swap(singVals(i),singVals(i+1));
|
|
694
|
-
U.col(i).swap(U.col(i+1));
|
|
695
|
-
if(m_compV) V.col(i).swap(V.col(i+1));
|
|
791
|
+
swap(singVals(i), singVals(i + 1));
|
|
792
|
+
U.col(i).swap(U.col(i + 1));
|
|
793
|
+
if (m_compV) V.col(i).swap(V.col(i + 1));
|
|
696
794
|
}
|
|
697
795
|
}
|
|
698
796
|
|
|
699
797
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
700
798
|
{
|
|
701
|
-
bool singular_values_sorted =
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
799
|
+
bool singular_values_sorted =
|
|
800
|
+
(((singVals.segment(1, actual_n - 1) - singVals.head(actual_n - 1))).array() >= 0).all();
|
|
801
|
+
if (!singular_values_sorted)
|
|
802
|
+
std::cout << "Singular values are not sorted: " << singVals.segment(1, actual_n).transpose() << "\n";
|
|
803
|
+
eigen_internal_assert(singular_values_sorted);
|
|
705
804
|
}
|
|
706
805
|
#endif
|
|
707
|
-
|
|
806
|
+
|
|
708
807
|
// Reverse order so that singular values in increased order
|
|
709
808
|
// Because of deflation, the zeros singular-values are already at the end
|
|
710
809
|
singVals.head(actual_n).reverseInPlace();
|
|
711
810
|
U.leftCols(actual_n).rowwise().reverseInPlace();
|
|
712
811
|
if (m_compV) V.leftCols(actual_n).rowwise().reverseInPlace();
|
|
713
|
-
|
|
812
|
+
|
|
714
813
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
715
|
-
JacobiSVD<MatrixXr> jsvd(m_computed.block(firstCol, firstCol, n, n)
|
|
814
|
+
JacobiSVD<MatrixXr> jsvd(m_computed.block(firstCol, firstCol, n, n));
|
|
716
815
|
std::cout << " * j: " << jsvd.singularValues().transpose() << "\n\n";
|
|
717
816
|
std::cout << " * sing-val: " << singVals.transpose() << "\n";
|
|
718
817
|
// std::cout << " * err: " << ((jsvd.singularValues()-singVals)>1e-13*singVals.norm()).transpose() << "\n";
|
|
719
818
|
#endif
|
|
720
819
|
}
|
|
721
820
|
|
|
722
|
-
template <typename MatrixType>
|
|
723
|
-
typename BDCSVD<MatrixType>::RealScalar BDCSVD<MatrixType>::secularEq(
|
|
724
|
-
|
|
821
|
+
template <typename MatrixType, int Options>
|
|
822
|
+
typename BDCSVD<MatrixType, Options>::RealScalar BDCSVD<MatrixType, Options>::secularEq(
|
|
823
|
+
RealScalar mu, const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm, const ArrayRef& diagShifted,
|
|
824
|
+
RealScalar shift) {
|
|
725
825
|
Index m = perm.size();
|
|
726
826
|
RealScalar res = Literal(1);
|
|
727
|
-
for(Index i=0; i<m; ++i)
|
|
728
|
-
{
|
|
827
|
+
for (Index i = 0; i < m; ++i) {
|
|
729
828
|
Index j = perm(i);
|
|
730
829
|
// The following expression could be rewritten to involve only a single division,
|
|
731
830
|
// but this would make the expression more sensitive to overflow.
|
|
732
831
|
res += (col0(j) / (diagShifted(j) - mu)) * (col0(j) / (diag(j) + shift + mu));
|
|
733
832
|
}
|
|
734
833
|
return res;
|
|
735
|
-
|
|
736
834
|
}
|
|
737
835
|
|
|
738
|
-
template <typename MatrixType>
|
|
739
|
-
void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& diag, const IndicesRef
|
|
740
|
-
|
|
741
|
-
{
|
|
836
|
+
template <typename MatrixType, int Options>
|
|
837
|
+
void BDCSVD<MatrixType, Options>::computeSingVals(const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm,
|
|
838
|
+
VectorType& singVals, ArrayRef shifts, ArrayRef mus) {
|
|
742
839
|
using std::abs;
|
|
743
|
-
using std::swap;
|
|
744
840
|
using std::sqrt;
|
|
841
|
+
using std::swap;
|
|
745
842
|
|
|
746
843
|
Index n = col0.size();
|
|
747
844
|
Index actual_n = n;
|
|
748
845
|
// Note that here actual_n is computed based on col0(i)==0 instead of diag(i)==0 as above
|
|
749
846
|
// because 1) we have diag(i)==0 => col0(i)==0 and 2) if col0(i)==0, then diag(i) is already a singular value.
|
|
750
|
-
while(actual_n>1 && col0(actual_n-1)
|
|
847
|
+
while (actual_n > 1 && numext::is_exactly_zero(col0(actual_n - 1))) --actual_n;
|
|
751
848
|
|
|
752
|
-
for (Index k = 0; k < n; ++k)
|
|
753
|
-
|
|
754
|
-
if (col0(k) == Literal(0) || actual_n==1)
|
|
755
|
-
{
|
|
849
|
+
for (Index k = 0; k < n; ++k) {
|
|
850
|
+
if (numext::is_exactly_zero(col0(k)) || actual_n == 1) {
|
|
756
851
|
// if col0(k) == 0, then entry is deflated, so singular value is on diagonal
|
|
757
852
|
// if actual_n==1, then the deflated problem is already diagonalized
|
|
758
|
-
singVals(k) = k==0 ? col0(0) : diag(k);
|
|
853
|
+
singVals(k) = k == 0 ? col0(0) : diag(k);
|
|
759
854
|
mus(k) = Literal(0);
|
|
760
|
-
shifts(k) = k==0 ? col0(0) : diag(k);
|
|
855
|
+
shifts(k) = k == 0 ? col0(0) : diag(k);
|
|
761
856
|
continue;
|
|
762
|
-
}
|
|
857
|
+
}
|
|
763
858
|
|
|
764
859
|
// otherwise, use secular equation to find singular value
|
|
765
860
|
RealScalar left = diag(k);
|
|
766
|
-
RealScalar right;
|
|
767
|
-
if(k==actual_n-1)
|
|
768
|
-
right = (diag(actual_n-1) + col0.matrix().norm());
|
|
769
|
-
else
|
|
770
|
-
{
|
|
861
|
+
RealScalar right; // was: = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm());
|
|
862
|
+
if (k == actual_n - 1)
|
|
863
|
+
right = (diag(actual_n - 1) + col0.matrix().norm());
|
|
864
|
+
else {
|
|
771
865
|
// Skip deflated singular values,
|
|
772
866
|
// recall that at this stage we assume that z[j]!=0 and all entries for which z[j]==0 have been put aside.
|
|
773
867
|
// This should be equivalent to using perm[]
|
|
774
|
-
Index l = k+1;
|
|
775
|
-
while(col0(l)
|
|
868
|
+
Index l = k + 1;
|
|
869
|
+
while (numext::is_exactly_zero(col0(l))) {
|
|
870
|
+
++l;
|
|
871
|
+
eigen_internal_assert(l < actual_n);
|
|
872
|
+
}
|
|
776
873
|
right = diag(l);
|
|
777
874
|
}
|
|
778
875
|
|
|
779
876
|
// first decide whether it's closer to the left end or the right end
|
|
780
|
-
RealScalar mid = left + (right-left) / Literal(2);
|
|
877
|
+
RealScalar mid = left + (right - left) / Literal(2);
|
|
781
878
|
RealScalar fMid = secularEq(mid, col0, diag, perm, diag, Literal(0));
|
|
782
879
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
783
|
-
std::cout << "right-left = " << right-left << "\n";
|
|
784
|
-
// std::cout << "fMid = " << fMid << " " << secularEq(mid-left, col0, diag, perm, ArrayXr(diag-left), left)
|
|
785
|
-
// << " " << secularEq(mid-right, col0, diag, perm, ArrayXr(diag-right), right) <<
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
<<
|
|
789
|
-
<<
|
|
790
|
-
<<
|
|
791
|
-
<<
|
|
792
|
-
<<
|
|
793
|
-
<<
|
|
794
|
-
<<
|
|
795
|
-
<<
|
|
796
|
-
<<
|
|
797
|
-
<<
|
|
798
|
-
<<
|
|
880
|
+
std::cout << "right-left = " << right - left << "\n";
|
|
881
|
+
// std::cout << "fMid = " << fMid << " " << secularEq(mid-left, col0, diag, perm, ArrayXr(diag-left), left)
|
|
882
|
+
// << " " << secularEq(mid-right, col0, diag, perm, ArrayXr(diag-right), right) <<
|
|
883
|
+
// "\n";
|
|
884
|
+
std::cout << " = " << secularEq(left + RealScalar(0.000001) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
885
|
+
<< secularEq(left + RealScalar(0.1) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
886
|
+
<< secularEq(left + RealScalar(0.2) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
887
|
+
<< secularEq(left + RealScalar(0.3) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
888
|
+
<< secularEq(left + RealScalar(0.4) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
889
|
+
<< secularEq(left + RealScalar(0.49) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
890
|
+
<< secularEq(left + RealScalar(0.5) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
891
|
+
<< secularEq(left + RealScalar(0.51) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
892
|
+
<< secularEq(left + RealScalar(0.6) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
893
|
+
<< secularEq(left + RealScalar(0.7) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
894
|
+
<< secularEq(left + RealScalar(0.8) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
895
|
+
<< secularEq(left + RealScalar(0.9) * (right - left), col0, diag, perm, diag, 0) << " "
|
|
896
|
+
<< secularEq(left + RealScalar(0.999999) * (right - left), col0, diag, perm, diag, 0) << "\n";
|
|
799
897
|
#endif
|
|
800
|
-
RealScalar shift = (k == actual_n-1 || fMid > Literal(0)) ? left : right;
|
|
801
|
-
|
|
898
|
+
RealScalar shift = (k == actual_n - 1 || fMid > Literal(0)) ? left : right;
|
|
899
|
+
|
|
802
900
|
// measure everything relative to shift
|
|
803
|
-
Map<ArrayXr> diagShifted(m_workspace.data()+4*n, n);
|
|
901
|
+
Map<ArrayXr> diagShifted(m_workspace.data() + 4 * n, n);
|
|
804
902
|
diagShifted = diag - shift;
|
|
805
903
|
|
|
806
|
-
if(k!=actual_n-1)
|
|
807
|
-
{
|
|
904
|
+
if (k != actual_n - 1) {
|
|
808
905
|
// check that after the shift, f(mid) is still negative:
|
|
809
906
|
RealScalar midShifted = (right - left) / RealScalar(2);
|
|
810
|
-
|
|
811
|
-
|
|
907
|
+
// we can test exact equality here, because shift comes from `... ? left : right`
|
|
908
|
+
if (numext::equal_strict(shift, right)) midShifted = -midShifted;
|
|
812
909
|
RealScalar fMidShifted = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
|
|
813
|
-
if(fMidShifted>0)
|
|
814
|
-
{
|
|
910
|
+
if (fMidShifted > 0) {
|
|
815
911
|
// fMid was erroneous, fix it:
|
|
816
|
-
shift =
|
|
912
|
+
shift = fMidShifted > Literal(0) ? left : right;
|
|
817
913
|
diagShifted = diag - shift;
|
|
818
914
|
}
|
|
819
915
|
}
|
|
820
|
-
|
|
916
|
+
|
|
821
917
|
// initial guess
|
|
822
918
|
RealScalar muPrev, muCur;
|
|
823
|
-
|
|
824
|
-
{
|
|
919
|
+
// we can test exact equality here, because shift comes from `... ? left : right`
|
|
920
|
+
if (numext::equal_strict(shift, left)) {
|
|
825
921
|
muPrev = (right - left) * RealScalar(0.1);
|
|
826
|
-
if (k == actual_n-1)
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
{
|
|
922
|
+
if (k == actual_n - 1)
|
|
923
|
+
muCur = right - left;
|
|
924
|
+
else
|
|
925
|
+
muCur = (right - left) * RealScalar(0.5);
|
|
926
|
+
} else {
|
|
831
927
|
muPrev = -(right - left) * RealScalar(0.1);
|
|
832
928
|
muCur = -(right - left) * RealScalar(0.5);
|
|
833
929
|
}
|
|
834
930
|
|
|
835
931
|
RealScalar fPrev = secularEq(muPrev, col0, diag, perm, diagShifted, shift);
|
|
836
932
|
RealScalar fCur = secularEq(muCur, col0, diag, perm, diagShifted, shift);
|
|
837
|
-
if (abs(fPrev) < abs(fCur))
|
|
838
|
-
{
|
|
933
|
+
if (abs(fPrev) < abs(fCur)) {
|
|
839
934
|
swap(fPrev, fCur);
|
|
840
935
|
swap(muPrev, muCur);
|
|
841
936
|
}
|
|
842
937
|
|
|
843
938
|
// rational interpolation: fit a function of the form a / mu + b through the two previous
|
|
844
939
|
// iterates and use its zero to compute the next iterate
|
|
845
|
-
bool useBisection = fPrev*fCur>Literal(0);
|
|
846
|
-
while (
|
|
847
|
-
|
|
940
|
+
bool useBisection = fPrev * fCur > Literal(0);
|
|
941
|
+
while (!numext::is_exactly_zero(fCur) &&
|
|
942
|
+
abs(muCur - muPrev) >
|
|
943
|
+
Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(muCur), abs(muPrev)) &&
|
|
944
|
+
abs(fCur - fPrev) > NumTraits<RealScalar>::epsilon() && !useBisection) {
|
|
848
945
|
++m_numIters;
|
|
849
946
|
|
|
850
947
|
// Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples.
|
|
851
|
-
RealScalar a = (fCur - fPrev) / (Literal(1)/muCur - Literal(1)/muPrev);
|
|
948
|
+
RealScalar a = (fCur - fPrev) / (Literal(1) / muCur - Literal(1) / muPrev);
|
|
852
949
|
RealScalar b = fCur - a / muCur;
|
|
853
950
|
// And find mu such that f(mu)==0:
|
|
854
|
-
RealScalar muZero = -a/b;
|
|
951
|
+
RealScalar muZero = -a / b;
|
|
855
952
|
RealScalar fZero = secularEq(muZero, col0, diag, perm, diagShifted, shift);
|
|
856
953
|
|
|
857
954
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
858
|
-
|
|
955
|
+
eigen_internal_assert((numext::isfinite)(fZero));
|
|
859
956
|
#endif
|
|
860
|
-
|
|
957
|
+
|
|
861
958
|
muPrev = muCur;
|
|
862
959
|
fPrev = fCur;
|
|
863
960
|
muCur = muZero;
|
|
864
961
|
fCur = fZero;
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
if (shift
|
|
868
|
-
if (
|
|
962
|
+
|
|
963
|
+
// we can test exact equality here, because shift comes from `... ? left : right`
|
|
964
|
+
if (numext::equal_strict(shift, left) && (muCur < Literal(0) || muCur > right - left)) useBisection = true;
|
|
965
|
+
if (numext::equal_strict(shift, right) && (muCur < -(right - left) || muCur > Literal(0))) useBisection = true;
|
|
966
|
+
if (abs(fCur) > abs(fPrev)) useBisection = true;
|
|
869
967
|
}
|
|
870
968
|
|
|
871
969
|
// fall back on bisection method if rational interpolation did not work
|
|
872
|
-
if (useBisection)
|
|
873
|
-
|
|
874
|
-
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
970
|
+
if (useBisection) {
|
|
971
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
875
972
|
std::cout << "useBisection for k = " << k << ", actual_n = " << actual_n << "\n";
|
|
876
973
|
#endif
|
|
877
974
|
RealScalar leftShifted, rightShifted;
|
|
878
|
-
|
|
879
|
-
{
|
|
975
|
+
// we can test exact equality here, because shift comes from `... ? left : right`
|
|
976
|
+
if (numext::equal_strict(shift, left)) {
|
|
880
977
|
// to avoid overflow, we must have mu > max(real_min, |z(k)|/sqrt(real_max)),
|
|
881
978
|
// the factor 2 is to be more conservative
|
|
882
|
-
leftShifted =
|
|
979
|
+
leftShifted =
|
|
980
|
+
numext::maxi<RealScalar>((std::numeric_limits<RealScalar>::min)(),
|
|
981
|
+
Literal(2) * abs(col0(k)) / sqrt((std::numeric_limits<RealScalar>::max)()));
|
|
883
982
|
|
|
884
983
|
// check that we did it right:
|
|
885
|
-
eigen_internal_assert(
|
|
984
|
+
eigen_internal_assert(
|
|
985
|
+
(numext::isfinite)((col0(k) / leftShifted) * (col0(k) / (diag(k) + shift + leftShifted))));
|
|
886
986
|
// I don't understand why the case k==0 would be special there:
|
|
887
987
|
// if (k == 0) rightShifted = right - left; else
|
|
888
|
-
rightShifted = (k==actual_n
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
{
|
|
988
|
+
rightShifted = (k == actual_n - 1)
|
|
989
|
+
? right
|
|
990
|
+
: ((right - left) * RealScalar(0.51)); // theoretically we can take 0.5, but let's be safe
|
|
991
|
+
} else {
|
|
892
992
|
leftShifted = -(right - left) * RealScalar(0.51);
|
|
893
|
-
if(k+1<n)
|
|
894
|
-
rightShifted = -numext::maxi<RealScalar>(
|
|
993
|
+
if (k + 1 < n)
|
|
994
|
+
rightShifted = -numext::maxi<RealScalar>((std::numeric_limits<RealScalar>::min)(),
|
|
995
|
+
abs(col0(k + 1)) / sqrt((std::numeric_limits<RealScalar>::max)()));
|
|
895
996
|
else
|
|
896
997
|
rightShifted = -(std::numeric_limits<RealScalar>::min)();
|
|
897
998
|
}
|
|
898
999
|
|
|
899
1000
|
RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift);
|
|
900
|
-
eigen_internal_assert(fLeft<Literal(0));
|
|
1001
|
+
eigen_internal_assert(fLeft < Literal(0));
|
|
901
1002
|
|
|
902
|
-
#if defined
|
|
1003
|
+
#if defined EIGEN_BDCSVD_DEBUG_VERBOSE || defined EIGEN_BDCSVD_SANITY_CHECKS || defined EIGEN_INTERNAL_DEBUGGING
|
|
903
1004
|
RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift);
|
|
904
1005
|
#endif
|
|
905
1006
|
|
|
906
1007
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
907
|
-
if(!(numext::isfinite)(fLeft))
|
|
1008
|
+
if (!(numext::isfinite)(fLeft))
|
|
908
1009
|
std::cout << "f(" << leftShifted << ") =" << fLeft << " ; " << left << " " << shift << " " << right << "\n";
|
|
909
|
-
|
|
1010
|
+
eigen_internal_assert((numext::isfinite)(fLeft));
|
|
910
1011
|
|
|
911
|
-
if(!(numext::isfinite)(fRight))
|
|
1012
|
+
if (!(numext::isfinite)(fRight))
|
|
912
1013
|
std::cout << "f(" << rightShifted << ") =" << fRight << " ; " << left << " " << shift << " " << right << "\n";
|
|
913
|
-
|
|
1014
|
+
// eigen_internal_assert((numext::isfinite)(fRight));
|
|
914
1015
|
#endif
|
|
915
|
-
|
|
916
|
-
#ifdef
|
|
917
|
-
if(!(fLeft * fRight<0))
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
<< "left==shift=" << bool(left==shift) << " ; left-shift = " << (left-shift) << "\n";
|
|
921
|
-
std::cout << "k=" << k << ", " <<
|
|
922
|
-
<< "[" << left << " .. " << right << "] -> [" << leftShifted << " " << rightShifted
|
|
923
|
-
<< " , f(right)=" << secularEq(0,
|
|
924
|
-
|
|
1016
|
+
|
|
1017
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1018
|
+
if (!(fLeft * fRight < 0)) {
|
|
1019
|
+
std::cout << "f(leftShifted) using leftShifted=" << leftShifted
|
|
1020
|
+
<< " ; diagShifted(1:10):" << diagShifted.head(10).transpose() << "\n ; "
|
|
1021
|
+
<< "left==shift=" << bool(left == shift) << " ; left-shift = " << (left - shift) << "\n";
|
|
1022
|
+
std::cout << "k=" << k << ", " << fLeft << " * " << fRight << " == " << fLeft * fRight << " ; "
|
|
1023
|
+
<< "[" << left << " .. " << right << "] -> [" << leftShifted << " " << rightShifted
|
|
1024
|
+
<< "], shift=" << shift << " , f(right)=" << secularEq(0, col0, diag, perm, diagShifted, shift)
|
|
1025
|
+
<< " == " << secularEq(right, col0, diag, perm, diag, 0) << " == " << fRight << "\n";
|
|
925
1026
|
}
|
|
926
1027
|
#endif
|
|
927
1028
|
eigen_internal_assert(fLeft * fRight < Literal(0));
|
|
928
1029
|
|
|
929
|
-
if(fLeft<Literal(0))
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
{
|
|
1030
|
+
if (fLeft < Literal(0)) {
|
|
1031
|
+
while (rightShifted - leftShifted > Literal(2) * NumTraits<RealScalar>::epsilon() *
|
|
1032
|
+
numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted))) {
|
|
933
1033
|
RealScalar midShifted = (leftShifted + rightShifted) / Literal(2);
|
|
934
1034
|
fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
|
|
935
1035
|
eigen_internal_assert((numext::isfinite)(fMid));
|
|
936
1036
|
|
|
937
|
-
if (fLeft * fMid < Literal(0))
|
|
938
|
-
{
|
|
1037
|
+
if (fLeft * fMid < Literal(0)) {
|
|
939
1038
|
rightShifted = midShifted;
|
|
940
|
-
}
|
|
941
|
-
else
|
|
942
|
-
{
|
|
1039
|
+
} else {
|
|
943
1040
|
leftShifted = midShifted;
|
|
944
1041
|
fLeft = fMid;
|
|
945
1042
|
}
|
|
946
1043
|
}
|
|
947
1044
|
muCur = (leftShifted + rightShifted) / Literal(2);
|
|
948
|
-
}
|
|
949
|
-
else
|
|
950
|
-
{
|
|
1045
|
+
} else {
|
|
951
1046
|
// We have a problem as shifting on the left or right give either a positive or negative value
|
|
952
1047
|
// at the middle of [left,right]...
|
|
953
|
-
// Instead
|
|
1048
|
+
// Instead of abbording or entering an infinite loop,
|
|
954
1049
|
// let's just use the middle as the estimated zero-crossing:
|
|
955
1050
|
muCur = (right - left) * RealScalar(0.5);
|
|
956
|
-
|
|
957
|
-
|
|
1051
|
+
// we can test exact equality here, because shift comes from `... ? left : right`
|
|
1052
|
+
if (numext::equal_strict(shift, right)) muCur = -muCur;
|
|
958
1053
|
}
|
|
959
1054
|
}
|
|
960
|
-
|
|
1055
|
+
|
|
961
1056
|
singVals[k] = shift + muCur;
|
|
962
1057
|
shifts[k] = shift;
|
|
963
1058
|
mus[k] = muCur;
|
|
964
1059
|
|
|
965
|
-
#ifdef
|
|
966
|
-
if(k+1<n)
|
|
967
|
-
std::cout << "found " << singVals[k] << " == " << shift << " + " << muCur << " from " << diag(k) << " .. "
|
|
1060
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1061
|
+
if (k + 1 < n)
|
|
1062
|
+
std::cout << "found " << singVals[k] << " == " << shift << " + " << muCur << " from " << diag(k) << " .. "
|
|
1063
|
+
<< diag(k + 1) << "\n";
|
|
968
1064
|
#endif
|
|
969
1065
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
970
|
-
|
|
971
|
-
|
|
1066
|
+
eigen_internal_assert(k == 0 || singVals[k] >= singVals[k - 1]);
|
|
1067
|
+
eigen_internal_assert(singVals[k] >= diag(k));
|
|
972
1068
|
#endif
|
|
973
1069
|
|
|
974
1070
|
// perturb singular value slightly if it equals diagonal entry to avoid division by zero later
|
|
975
1071
|
// (deflation is supposed to avoid this from happening)
|
|
976
1072
|
// - this does no seem to be necessary anymore -
|
|
977
|
-
//
|
|
978
|
-
//
|
|
1073
|
+
// if (singVals[k] == left) singVals[k] *= 1 + NumTraits<RealScalar>::epsilon();
|
|
1074
|
+
// if (singVals[k] == right) singVals[k] *= 1 - NumTraits<RealScalar>::epsilon();
|
|
979
1075
|
}
|
|
980
1076
|
}
|
|
981
1077
|
|
|
982
|
-
|
|
983
1078
|
// zhat is perturbation of col0 for which singular vectors can be computed stably (see Section 3.1)
|
|
984
|
-
template <typename MatrixType>
|
|
985
|
-
void BDCSVD<MatrixType>::perturbCol0
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
{
|
|
1079
|
+
template <typename MatrixType, int Options>
|
|
1080
|
+
void BDCSVD<MatrixType, Options>::perturbCol0(const ArrayRef& col0, const ArrayRef& diag, const IndicesRef& perm,
|
|
1081
|
+
const VectorType& singVals, const ArrayRef& shifts, const ArrayRef& mus,
|
|
1082
|
+
ArrayRef zhat) {
|
|
989
1083
|
using std::sqrt;
|
|
990
1084
|
Index n = col0.size();
|
|
991
1085
|
Index m = perm.size();
|
|
992
|
-
if(m==0)
|
|
993
|
-
{
|
|
1086
|
+
if (m == 0) {
|
|
994
1087
|
zhat.setZero();
|
|
995
1088
|
return;
|
|
996
1089
|
}
|
|
997
|
-
Index lastIdx = perm(m-1);
|
|
1090
|
+
Index lastIdx = perm(m - 1);
|
|
998
1091
|
// The offset permits to skip deflated entries while computing zhat
|
|
999
|
-
for (Index k = 0; k < n; ++k)
|
|
1000
|
-
|
|
1001
|
-
if (col0(k) == Literal(0)) // deflated
|
|
1092
|
+
for (Index k = 0; k < n; ++k) {
|
|
1093
|
+
if (numext::is_exactly_zero(col0(k))) // deflated
|
|
1002
1094
|
zhat(k) = Literal(0);
|
|
1003
|
-
else
|
|
1004
|
-
{
|
|
1095
|
+
else {
|
|
1005
1096
|
// see equation (3.6)
|
|
1006
1097
|
RealScalar dk = diag(k);
|
|
1007
1098
|
RealScalar prod = (singVals(lastIdx) + dk) * (mus(lastIdx) + (shifts(lastIdx) - dk));
|
|
1008
1099
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1009
|
-
if(prod<0) {
|
|
1100
|
+
if (prod < 0) {
|
|
1010
1101
|
std::cout << "k = " << k << " ; z(k)=" << col0(k) << ", diag(k)=" << dk << "\n";
|
|
1011
|
-
std::cout << "prod = "
|
|
1012
|
-
|
|
1102
|
+
std::cout << "prod = "
|
|
1103
|
+
<< "(" << singVals(lastIdx) << " + " << dk << ") * (" << mus(lastIdx) << " + (" << shifts(lastIdx)
|
|
1104
|
+
<< " - " << dk << "))"
|
|
1105
|
+
<< "\n";
|
|
1106
|
+
std::cout << " = " << singVals(lastIdx) + dk << " * " << mus(lastIdx) + (shifts(lastIdx) - dk) << "\n";
|
|
1013
1107
|
}
|
|
1014
|
-
|
|
1108
|
+
eigen_internal_assert(prod >= 0);
|
|
1015
1109
|
#endif
|
|
1016
1110
|
|
|
1017
|
-
for(Index l = 0; l<m; ++l)
|
|
1018
|
-
{
|
|
1111
|
+
for (Index l = 0; l < m; ++l) {
|
|
1019
1112
|
Index i = perm(l);
|
|
1020
|
-
if(i!=k)
|
|
1021
|
-
{
|
|
1113
|
+
if (i != k) {
|
|
1022
1114
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1023
|
-
if(i>=k && (l==0 || l-1>=m))
|
|
1024
|
-
{
|
|
1115
|
+
if (i >= k && (l == 0 || l - 1 >= m)) {
|
|
1025
1116
|
std::cout << "Error in perturbCol0\n";
|
|
1026
|
-
std::cout << " " << k << "/" << n << " "
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
std::cout << " " <<
|
|
1117
|
+
std::cout << " " << k << "/" << n << " " << l << "/" << m << " " << i << "/" << n << " ; " << col0(k)
|
|
1118
|
+
<< " " << diag(k) << " "
|
|
1119
|
+
<< "\n";
|
|
1120
|
+
std::cout << " " << diag(i) << "\n";
|
|
1121
|
+
Index j = (i < k /*|| l==0*/) ? i : perm(l - 1);
|
|
1122
|
+
std::cout << " "
|
|
1123
|
+
<< "j=" << j << "\n";
|
|
1030
1124
|
}
|
|
1031
1125
|
#endif
|
|
1032
|
-
Index j = i<k ? i : perm(l-1);
|
|
1126
|
+
Index j = i < k ? i : l > 0 ? perm(l - 1) : i;
|
|
1033
1127
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1034
|
-
if(!(dk!=Literal(0) || diag(i)!=Literal(0)))
|
|
1035
|
-
{
|
|
1128
|
+
if (!(dk != Literal(0) || diag(i) != Literal(0))) {
|
|
1036
1129
|
std::cout << "k=" << k << ", i=" << i << ", l=" << l << ", perm.size()=" << perm.size() << "\n";
|
|
1037
1130
|
}
|
|
1038
|
-
|
|
1131
|
+
eigen_internal_assert(dk != Literal(0) || diag(i) != Literal(0));
|
|
1039
1132
|
#endif
|
|
1040
|
-
prod *= ((singVals(j)+dk) / ((diag(i)+dk))) * ((mus(j)+(shifts(j)-dk)) / ((diag(i)-dk)));
|
|
1133
|
+
prod *= ((singVals(j) + dk) / ((diag(i) + dk))) * ((mus(j) + (shifts(j) - dk)) / ((diag(i) - dk)));
|
|
1041
1134
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1042
|
-
|
|
1135
|
+
eigen_internal_assert(prod >= 0);
|
|
1043
1136
|
#endif
|
|
1044
1137
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1045
|
-
if(i!=k &&
|
|
1046
|
-
|
|
1047
|
-
|
|
1138
|
+
if (i != k &&
|
|
1139
|
+
numext::abs(((singVals(j) + dk) * (mus(j) + (shifts(j) - dk))) / ((diag(i) + dk) * (diag(i) - dk)) - 1) >
|
|
1140
|
+
0.9)
|
|
1141
|
+
std::cout << " "
|
|
1142
|
+
<< ((singVals(j) + dk) * (mus(j) + (shifts(j) - dk))) / ((diag(i) + dk) * (diag(i) - dk))
|
|
1143
|
+
<< " == (" << (singVals(j) + dk) << " * " << (mus(j) + (shifts(j) - dk)) << ") / ("
|
|
1144
|
+
<< (diag(i) + dk) << " * " << (diag(i) - dk) << ")\n";
|
|
1048
1145
|
#endif
|
|
1049
1146
|
}
|
|
1050
1147
|
}
|
|
1051
1148
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1052
|
-
std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(lastIdx) + dk) << " * "
|
|
1149
|
+
std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(lastIdx) + dk) << " * "
|
|
1150
|
+
<< mus(lastIdx) + shifts(lastIdx) << " - " << dk << "\n";
|
|
1053
1151
|
#endif
|
|
1054
1152
|
RealScalar tmp = sqrt(prod);
|
|
1055
1153
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1056
|
-
|
|
1154
|
+
eigen_internal_assert((numext::isfinite)(tmp));
|
|
1057
1155
|
#endif
|
|
1058
1156
|
zhat(k) = col0(k) > Literal(0) ? RealScalar(tmp) : RealScalar(-tmp);
|
|
1059
1157
|
}
|
|
@@ -1061,254 +1159,246 @@ void BDCSVD<MatrixType>::perturbCol0
|
|
|
1061
1159
|
}
|
|
1062
1160
|
|
|
1063
1161
|
// compute singular vectors
|
|
1064
|
-
template <typename MatrixType>
|
|
1065
|
-
void BDCSVD<MatrixType>::computeSingVecs
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
{
|
|
1162
|
+
template <typename MatrixType, int Options>
|
|
1163
|
+
void BDCSVD<MatrixType, Options>::computeSingVecs(const ArrayRef& zhat, const ArrayRef& diag, const IndicesRef& perm,
|
|
1164
|
+
const VectorType& singVals, const ArrayRef& shifts,
|
|
1165
|
+
const ArrayRef& mus, MatrixXr& U, MatrixXr& V) {
|
|
1069
1166
|
Index n = zhat.size();
|
|
1070
1167
|
Index m = perm.size();
|
|
1071
|
-
|
|
1072
|
-
for (Index k = 0; k < n; ++k)
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
{
|
|
1076
|
-
U.col(k) = VectorType::Unit(n+1, k);
|
|
1168
|
+
|
|
1169
|
+
for (Index k = 0; k < n; ++k) {
|
|
1170
|
+
if (numext::is_exactly_zero(zhat(k))) {
|
|
1171
|
+
U.col(k) = VectorType::Unit(n + 1, k);
|
|
1077
1172
|
if (m_compV) V.col(k) = VectorType::Unit(n, k);
|
|
1078
|
-
}
|
|
1079
|
-
else
|
|
1080
|
-
{
|
|
1173
|
+
} else {
|
|
1081
1174
|
U.col(k).setZero();
|
|
1082
|
-
for(Index l=0;l<m
|
|
1083
|
-
{
|
|
1175
|
+
for (Index l = 0; l < m; ++l) {
|
|
1084
1176
|
Index i = perm(l);
|
|
1085
|
-
U(i,k) = zhat(i)/(((diag(i) - shifts(k)) - mus(k))
|
|
1177
|
+
U(i, k) = zhat(i) / (((diag(i) - shifts(k)) - mus(k))) / ((diag(i) + singVals[k]));
|
|
1086
1178
|
}
|
|
1087
|
-
U(n,k) = Literal(0);
|
|
1179
|
+
U(n, k) = Literal(0);
|
|
1088
1180
|
U.col(k).normalize();
|
|
1089
|
-
|
|
1090
|
-
if (m_compV)
|
|
1091
|
-
{
|
|
1181
|
+
|
|
1182
|
+
if (m_compV) {
|
|
1092
1183
|
V.col(k).setZero();
|
|
1093
|
-
for(Index l=1;l<m
|
|
1094
|
-
{
|
|
1184
|
+
for (Index l = 1; l < m; ++l) {
|
|
1095
1185
|
Index i = perm(l);
|
|
1096
|
-
V(i,k) = diag(i) * zhat(i) / (((diag(i) - shifts(k)) - mus(k))
|
|
1186
|
+
V(i, k) = diag(i) * zhat(i) / (((diag(i) - shifts(k)) - mus(k))) / ((diag(i) + singVals[k]));
|
|
1097
1187
|
}
|
|
1098
|
-
V(0,k) = Literal(-1);
|
|
1188
|
+
V(0, k) = Literal(-1);
|
|
1099
1189
|
V.col(k).normalize();
|
|
1100
1190
|
}
|
|
1101
1191
|
}
|
|
1102
1192
|
}
|
|
1103
|
-
U.col(n) = VectorType::Unit(n+1, n);
|
|
1193
|
+
U.col(n) = VectorType::Unit(n + 1, n);
|
|
1104
1194
|
}
|
|
1105
1195
|
|
|
1106
|
-
|
|
1107
1196
|
// page 12_13
|
|
1108
1197
|
// i >= 1, di almost null and zi non null.
|
|
1109
|
-
// We use a rotation to zero out zi applied to the left of M
|
|
1110
|
-
template <typename MatrixType>
|
|
1111
|
-
void BDCSVD<MatrixType>::deflation43(
|
|
1112
|
-
{
|
|
1198
|
+
// We use a rotation to zero out zi applied to the left of M, and set di = 0.
|
|
1199
|
+
template <typename MatrixType, int Options>
|
|
1200
|
+
void BDCSVD<MatrixType, Options>::deflation43(Index firstCol, Index shift, Index i, Index size) {
|
|
1113
1201
|
using std::abs;
|
|
1114
|
-
using std::sqrt;
|
|
1115
1202
|
using std::pow;
|
|
1203
|
+
using std::sqrt;
|
|
1116
1204
|
Index start = firstCol + shift;
|
|
1117
1205
|
RealScalar c = m_computed(start, start);
|
|
1118
|
-
RealScalar s = m_computed(start+i, start);
|
|
1119
|
-
RealScalar r = numext::hypot(c,s);
|
|
1120
|
-
if (r
|
|
1121
|
-
|
|
1122
|
-
m_computed(start+i, start+i) = Literal(0);
|
|
1206
|
+
RealScalar s = m_computed(start + i, start);
|
|
1207
|
+
RealScalar r = numext::hypot(c, s);
|
|
1208
|
+
if (numext::is_exactly_zero(r)) {
|
|
1209
|
+
m_computed(start + i, start + i) = Literal(0);
|
|
1123
1210
|
return;
|
|
1124
1211
|
}
|
|
1125
|
-
m_computed(start,start) = r;
|
|
1126
|
-
m_computed(start+i, start) = Literal(0);
|
|
1127
|
-
m_computed(start+i, start+i) = Literal(0);
|
|
1128
|
-
|
|
1129
|
-
JacobiRotation<RealScalar> J(c/r,-s/r);
|
|
1130
|
-
if (m_compU) m_naiveU.middleRows(firstCol, size+1).applyOnTheRight(firstCol, firstCol+i, J);
|
|
1131
|
-
else m_naiveU.applyOnTheRight(firstCol, firstCol+i, J);
|
|
1132
|
-
}// end deflation 43
|
|
1212
|
+
m_computed(start, start) = r;
|
|
1213
|
+
m_computed(start + i, start) = Literal(0);
|
|
1214
|
+
m_computed(start + i, start + i) = Literal(0);
|
|
1133
1215
|
|
|
1216
|
+
JacobiRotation<RealScalar> J(c / r, -s / r);
|
|
1217
|
+
if (m_compU)
|
|
1218
|
+
m_naiveU.middleRows(firstCol, size + 1).applyOnTheRight(firstCol, firstCol + i, J);
|
|
1219
|
+
else
|
|
1220
|
+
m_naiveU.applyOnTheRight(firstCol, firstCol + i, J);
|
|
1221
|
+
} // end deflation 43
|
|
1134
1222
|
|
|
1135
1223
|
// page 13
|
|
1136
|
-
// i,j >= 1, i
|
|
1137
|
-
// We apply two rotations to have
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
{
|
|
1224
|
+
// i,j >= 1, i > j, and |di - dj| < epsilon * norm2(M)
|
|
1225
|
+
// We apply two rotations to have zi = 0, and dj = di.
|
|
1226
|
+
template <typename MatrixType, int Options>
|
|
1227
|
+
void BDCSVD<MatrixType, Options>::deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW,
|
|
1228
|
+
Index i, Index j, Index size) {
|
|
1142
1229
|
using std::abs;
|
|
1143
|
-
using std::sqrt;
|
|
1144
1230
|
using std::conj;
|
|
1145
1231
|
using std::pow;
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
RealScalar
|
|
1149
|
-
|
|
1232
|
+
using std::sqrt;
|
|
1233
|
+
|
|
1234
|
+
RealScalar s = m_computed(firstColm + i, firstColm);
|
|
1235
|
+
RealScalar c = m_computed(firstColm + j, firstColm);
|
|
1236
|
+
RealScalar r = numext::hypot(c, s);
|
|
1237
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1150
1238
|
std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; "
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
<< m_computed(firstColm + i, firstColm+i) << " "
|
|
1157
|
-
<< m_computed(firstColm + i+1, firstColm+i+1) << " "
|
|
1158
|
-
<< m_computed(firstColm + i+2, firstColm+i+2) << "\n";
|
|
1239
|
+
<< m_computed(firstColm + i - 1, firstColm) << " " << m_computed(firstColm + i, firstColm) << " "
|
|
1240
|
+
<< m_computed(firstColm + i + 1, firstColm) << " " << m_computed(firstColm + i + 2, firstColm) << "\n";
|
|
1241
|
+
std::cout << m_computed(firstColm + i - 1, firstColm + i - 1) << " " << m_computed(firstColm + i, firstColm + i)
|
|
1242
|
+
<< " " << m_computed(firstColm + i + 1, firstColm + i + 1) << " "
|
|
1243
|
+
<< m_computed(firstColm + i + 2, firstColm + i + 2) << "\n";
|
|
1159
1244
|
#endif
|
|
1160
|
-
if (r
|
|
1161
|
-
|
|
1162
|
-
m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j);
|
|
1245
|
+
if (numext::is_exactly_zero(r)) {
|
|
1246
|
+
m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
|
|
1163
1247
|
return;
|
|
1164
1248
|
}
|
|
1165
|
-
c/=r;
|
|
1166
|
-
s/=r;
|
|
1167
|
-
m_computed(firstColm +
|
|
1249
|
+
c /= r;
|
|
1250
|
+
s /= r;
|
|
1251
|
+
m_computed(firstColm + j, firstColm) = r;
|
|
1168
1252
|
m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
|
|
1169
|
-
m_computed(firstColm +
|
|
1170
|
-
|
|
1171
|
-
JacobiRotation<RealScalar> J(c,-s);
|
|
1172
|
-
if (m_compU) m_naiveU.middleRows(firstColu, size+1).applyOnTheRight(firstColu + i, firstColu + j, J);
|
|
1173
|
-
else m_naiveU.applyOnTheRight(firstColu+i, firstColu+j, J);
|
|
1174
|
-
if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J);
|
|
1175
|
-
}// end deflation 44
|
|
1253
|
+
m_computed(firstColm + i, firstColm) = Literal(0);
|
|
1176
1254
|
|
|
1255
|
+
JacobiRotation<RealScalar> J(c, -s);
|
|
1256
|
+
if (m_compU)
|
|
1257
|
+
m_naiveU.middleRows(firstColu, size + 1).applyOnTheRight(firstColu + j, firstColu + i, J);
|
|
1258
|
+
else
|
|
1259
|
+
m_naiveU.applyOnTheRight(firstColu + j, firstColu + i, J);
|
|
1260
|
+
if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + j, firstColW + i, J);
|
|
1261
|
+
} // end deflation 44
|
|
1177
1262
|
|
|
1178
1263
|
// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive]
|
|
1179
|
-
template <typename MatrixType>
|
|
1180
|
-
void BDCSVD<MatrixType>::deflation(
|
|
1181
|
-
{
|
|
1182
|
-
using std::sqrt;
|
|
1264
|
+
template <typename MatrixType, int Options>
|
|
1265
|
+
void BDCSVD<MatrixType, Options>::deflation(Index firstCol, Index lastCol, Index k, Index firstRowW, Index firstColW,
|
|
1266
|
+
Index shift) {
|
|
1183
1267
|
using std::abs;
|
|
1268
|
+
using std::sqrt;
|
|
1184
1269
|
const Index length = lastCol + 1 - firstCol;
|
|
1185
|
-
|
|
1186
|
-
Block<MatrixXr,Dynamic,1> col0(m_computed, firstCol+shift, firstCol+shift, length, 1);
|
|
1270
|
+
|
|
1271
|
+
Block<MatrixXr, Dynamic, 1> col0(m_computed, firstCol + shift, firstCol + shift, length, 1);
|
|
1187
1272
|
Diagonal<MatrixXr> fulldiag(m_computed);
|
|
1188
|
-
VectorBlock<Diagonal<MatrixXr>,Dynamic> diag(fulldiag, firstCol+shift, length);
|
|
1189
|
-
|
|
1273
|
+
VectorBlock<Diagonal<MatrixXr>, Dynamic> diag(fulldiag, firstCol + shift, length);
|
|
1274
|
+
|
|
1190
1275
|
const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
|
|
1191
|
-
RealScalar maxDiag = diag.tail((std::max)(Index(1),length-1)).cwiseAbs().maxCoeff();
|
|
1192
|
-
RealScalar epsilon_strict = numext::maxi<RealScalar>(considerZero,NumTraits<RealScalar>::epsilon() * maxDiag);
|
|
1193
|
-
RealScalar epsilon_coarse =
|
|
1194
|
-
|
|
1276
|
+
RealScalar maxDiag = diag.tail((std::max)(Index(1), length - 1)).cwiseAbs().maxCoeff();
|
|
1277
|
+
RealScalar epsilon_strict = numext::maxi<RealScalar>(considerZero, NumTraits<RealScalar>::epsilon() * maxDiag);
|
|
1278
|
+
RealScalar epsilon_coarse =
|
|
1279
|
+
Literal(8) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(col0.cwiseAbs().maxCoeff(), maxDiag);
|
|
1280
|
+
|
|
1195
1281
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1282
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
1283
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
1284
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
1199
1285
|
#endif
|
|
1200
1286
|
|
|
1201
|
-
#ifdef
|
|
1202
|
-
std::cout << "\ndeflate:" << diag.head(k+1).transpose() << " | "
|
|
1287
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1288
|
+
std::cout << "\ndeflate:" << diag.head(k + 1).transpose() << " | "
|
|
1289
|
+
<< diag.segment(k + 1, length - k - 1).transpose() << "\n";
|
|
1203
1290
|
#endif
|
|
1204
|
-
|
|
1205
|
-
//condition 4.1
|
|
1206
|
-
if (diag(0) < epsilon_coarse)
|
|
1207
|
-
|
|
1208
|
-
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1291
|
+
|
|
1292
|
+
// condition 4.1
|
|
1293
|
+
if (diag(0) < epsilon_coarse) {
|
|
1294
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1209
1295
|
std::cout << "deflation 4.1, because " << diag(0) << " < " << epsilon_coarse << "\n";
|
|
1210
1296
|
#endif
|
|
1211
1297
|
diag(0) = epsilon_coarse;
|
|
1212
1298
|
}
|
|
1213
1299
|
|
|
1214
|
-
//condition 4.2
|
|
1215
|
-
for (Index i=1;i<length
|
|
1216
|
-
if (abs(col0(i)) < epsilon_strict)
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1300
|
+
// condition 4.2
|
|
1301
|
+
for (Index i = 1; i < length; ++i)
|
|
1302
|
+
if (abs(col0(i)) < epsilon_strict) {
|
|
1303
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1304
|
+
std::cout << "deflation 4.2, set z(" << i << ") to zero because " << abs(col0(i)) << " < " << epsilon_strict
|
|
1305
|
+
<< " (diag(" << i << ")=" << diag(i) << ")\n";
|
|
1220
1306
|
#endif
|
|
1221
1307
|
col0(i) = Literal(0);
|
|
1222
1308
|
}
|
|
1223
1309
|
|
|
1224
|
-
//condition 4.3
|
|
1225
|
-
for (Index i=1;i<length; i++)
|
|
1226
|
-
if (diag(i) < epsilon_coarse)
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1310
|
+
// condition 4.3
|
|
1311
|
+
for (Index i = 1; i < length; i++)
|
|
1312
|
+
if (diag(i) < epsilon_coarse) {
|
|
1313
|
+
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1314
|
+
std::cout << "deflation 4.3, cancel z(" << i << ")=" << col0(i) << " because diag(" << i << ")=" << diag(i)
|
|
1315
|
+
<< " < " << epsilon_coarse << "\n";
|
|
1230
1316
|
#endif
|
|
1231
1317
|
deflation43(firstCol, shift, i, length);
|
|
1232
1318
|
}
|
|
1233
1319
|
|
|
1234
1320
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1321
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
1322
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
1323
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
1238
1324
|
#endif
|
|
1239
1325
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1240
1326
|
std::cout << "to be sorted: " << diag.transpose() << "\n\n";
|
|
1241
1327
|
std::cout << " : " << col0.transpose() << "\n\n";
|
|
1242
1328
|
#endif
|
|
1243
1329
|
{
|
|
1244
|
-
// Check for total deflation
|
|
1245
|
-
// If we have a total deflation, then we have to consider col0(0)==diag(0) as a singular value during sorting
|
|
1246
|
-
bool total_deflation = (col0.tail(length-1).array()<considerZero).all();
|
|
1247
|
-
|
|
1330
|
+
// Check for total deflation:
|
|
1331
|
+
// If we have a total deflation, then we have to consider col0(0)==diag(0) as a singular value during sorting.
|
|
1332
|
+
const bool total_deflation = (col0.tail(length - 1).array().abs() < considerZero).all();
|
|
1333
|
+
|
|
1248
1334
|
// Sort the diagonal entries, since diag(1:k-1) and diag(k:length) are already sorted, let's do a sorted merge.
|
|
1249
1335
|
// First, compute the respective permutation.
|
|
1250
|
-
Index
|
|
1336
|
+
Index* permutation = m_workspaceI.data();
|
|
1251
1337
|
{
|
|
1252
1338
|
permutation[0] = 0;
|
|
1253
1339
|
Index p = 1;
|
|
1254
|
-
|
|
1340
|
+
|
|
1255
1341
|
// Move deflated diagonal entries at the end.
|
|
1256
|
-
for(Index i=1; i<length; ++i)
|
|
1257
|
-
if(
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
else if (diag(i) < diag(j))
|
|
1266
|
-
|
|
1342
|
+
for (Index i = 1; i < length; ++i)
|
|
1343
|
+
if (diag(i) < considerZero) permutation[p++] = i;
|
|
1344
|
+
|
|
1345
|
+
Index i = 1, j = k + 1;
|
|
1346
|
+
for (; p < length; ++p) {
|
|
1347
|
+
if (i > k)
|
|
1348
|
+
permutation[p] = j++;
|
|
1349
|
+
else if (j >= length)
|
|
1350
|
+
permutation[p] = i++;
|
|
1351
|
+
else if (diag(i) < diag(j))
|
|
1352
|
+
permutation[p] = j++;
|
|
1353
|
+
else
|
|
1354
|
+
permutation[p] = i++;
|
|
1267
1355
|
}
|
|
1268
1356
|
}
|
|
1269
|
-
|
|
1357
|
+
|
|
1270
1358
|
// If we have a total deflation, then we have to insert diag(0) at the right place
|
|
1271
|
-
if(total_deflation)
|
|
1272
|
-
|
|
1273
|
-
for(Index i=1; i<length; ++i)
|
|
1274
|
-
{
|
|
1359
|
+
if (total_deflation) {
|
|
1360
|
+
for (Index i = 1; i < length; ++i) {
|
|
1275
1361
|
Index pi = permutation[i];
|
|
1276
|
-
if(
|
|
1277
|
-
permutation[i-1] = permutation[i];
|
|
1278
|
-
else
|
|
1279
|
-
|
|
1280
|
-
permutation[i-1] = 0;
|
|
1362
|
+
if (diag(pi) < considerZero || diag(0) < diag(pi))
|
|
1363
|
+
permutation[i - 1] = permutation[i];
|
|
1364
|
+
else {
|
|
1365
|
+
permutation[i - 1] = 0;
|
|
1281
1366
|
break;
|
|
1282
1367
|
}
|
|
1283
1368
|
}
|
|
1284
1369
|
}
|
|
1285
|
-
|
|
1370
|
+
|
|
1286
1371
|
// Current index of each col, and current column of each index
|
|
1287
|
-
Index
|
|
1288
|
-
Index
|
|
1289
|
-
|
|
1290
|
-
for(int pos = 0; pos< length; pos++)
|
|
1291
|
-
{
|
|
1372
|
+
Index* realInd = m_workspaceI.data() + length;
|
|
1373
|
+
Index* realCol = m_workspaceI.data() + 2 * length;
|
|
1374
|
+
|
|
1375
|
+
for (int pos = 0; pos < length; pos++) {
|
|
1292
1376
|
realCol[pos] = pos;
|
|
1293
1377
|
realInd[pos] = pos;
|
|
1294
1378
|
}
|
|
1295
|
-
|
|
1296
|
-
for(Index i = total_deflation?0:1; i < length; i++)
|
|
1297
|
-
|
|
1298
|
-
const Index pi = permutation[length - (total_deflation ? i+1 : i)];
|
|
1379
|
+
|
|
1380
|
+
for (Index i = total_deflation ? 0 : 1; i < length; i++) {
|
|
1381
|
+
const Index pi = permutation[length - (total_deflation ? i + 1 : i)];
|
|
1299
1382
|
const Index J = realCol[pi];
|
|
1300
|
-
|
|
1383
|
+
|
|
1301
1384
|
using std::swap;
|
|
1302
1385
|
// swap diagonal and first column entries:
|
|
1303
1386
|
swap(diag(i), diag(J));
|
|
1304
|
-
if(i!=0 && J!=0) swap(col0(i), col0(J));
|
|
1387
|
+
if (i != 0 && J != 0) swap(col0(i), col0(J));
|
|
1305
1388
|
|
|
1306
1389
|
// change columns
|
|
1307
|
-
if (m_compU)
|
|
1308
|
-
|
|
1309
|
-
|
|
1390
|
+
if (m_compU)
|
|
1391
|
+
m_naiveU.col(firstCol + i)
|
|
1392
|
+
.segment(firstCol, length + 1)
|
|
1393
|
+
.swap(m_naiveU.col(firstCol + J).segment(firstCol, length + 1));
|
|
1394
|
+
else
|
|
1395
|
+
m_naiveU.col(firstCol + i).segment(0, 2).swap(m_naiveU.col(firstCol + J).segment(0, 2));
|
|
1396
|
+
if (m_compV)
|
|
1397
|
+
m_naiveV.col(firstColW + i)
|
|
1398
|
+
.segment(firstRowW, length)
|
|
1399
|
+
.swap(m_naiveV.col(firstColW + J).segment(firstRowW, length));
|
|
1310
1400
|
|
|
1311
|
-
//update real pos
|
|
1401
|
+
// update real pos
|
|
1312
1402
|
const Index realI = realInd[i];
|
|
1313
1403
|
realCol[realI] = J;
|
|
1314
1404
|
realCol[pi] = i;
|
|
@@ -1320,47 +1410,61 @@ void BDCSVD<MatrixType>::deflation(Eigen::Index firstCol, Eigen::Index lastCol,
|
|
|
1320
1410
|
std::cout << "sorted: " << diag.transpose().format(bdcsvdfmt) << "\n";
|
|
1321
1411
|
std::cout << " : " << col0.transpose() << "\n\n";
|
|
1322
1412
|
#endif
|
|
1323
|
-
|
|
1324
|
-
//condition 4.4
|
|
1413
|
+
|
|
1414
|
+
// condition 4.4
|
|
1325
1415
|
{
|
|
1326
|
-
Index i = length-1;
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1416
|
+
Index i = length - 1;
|
|
1417
|
+
// Find last non-deflated entry.
|
|
1418
|
+
while (i > 0 && (diag(i) < considerZero || abs(col0(i)) < considerZero)) --i;
|
|
1419
|
+
|
|
1420
|
+
for (; i > 1; --i)
|
|
1421
|
+
if ((diag(i) - diag(i - 1)) < epsilon_strict) {
|
|
1331
1422
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
|
1332
|
-
std::cout << "deflation 4.4 with i = " << i << " because " << diag(i) << " - " << diag(i
|
|
1423
|
+
std::cout << "deflation 4.4 with i = " << i << " because " << diag(i) << " - " << diag(i - 1)
|
|
1424
|
+
<< " == " << (diag(i) - diag(i - 1)) << " < " << epsilon_strict << "\n";
|
|
1333
1425
|
#endif
|
|
1334
|
-
eigen_internal_assert(abs(diag(i) - diag(i-1))<epsilon_coarse &&
|
|
1335
|
-
|
|
1426
|
+
eigen_internal_assert(abs(diag(i) - diag(i - 1)) < epsilon_coarse &&
|
|
1427
|
+
" diagonal entries are not properly sorted");
|
|
1428
|
+
deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i, i - 1, length);
|
|
1336
1429
|
}
|
|
1337
1430
|
}
|
|
1338
|
-
|
|
1431
|
+
|
|
1339
1432
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1340
|
-
for(Index j=2;j<length
|
|
1341
|
-
assert(diag(j-1)<=diag(j) || abs(diag(j))<considerZero);
|
|
1433
|
+
for (Index j = 2; j < length; ++j) eigen_internal_assert(diag(j - 1) <= diag(j) || abs(diag(j)) < considerZero);
|
|
1342
1434
|
#endif
|
|
1343
|
-
|
|
1435
|
+
|
|
1344
1436
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1437
|
+
eigen_internal_assert(m_naiveU.allFinite());
|
|
1438
|
+
eigen_internal_assert(m_naiveV.allFinite());
|
|
1439
|
+
eigen_internal_assert(m_computed.allFinite());
|
|
1348
1440
|
#endif
|
|
1349
|
-
}//end deflation
|
|
1441
|
+
} // end deflation
|
|
1350
1442
|
|
|
1351
1443
|
/** \svd_module
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
template<typename Derived>
|
|
1358
|
-
|
|
1359
|
-
MatrixBase<Derived>::bdcSvd(
|
|
1360
|
-
|
|
1361
|
-
|
|
1444
|
+
*
|
|
1445
|
+
* \return the singular value decomposition of \c *this computed by Divide & Conquer algorithm
|
|
1446
|
+
*
|
|
1447
|
+
* \sa class BDCSVD
|
|
1448
|
+
*/
|
|
1449
|
+
template <typename Derived>
|
|
1450
|
+
template <int Options>
|
|
1451
|
+
BDCSVD<typename MatrixBase<Derived>::PlainObject, Options> MatrixBase<Derived>::bdcSvd() const {
|
|
1452
|
+
return BDCSVD<PlainObject, Options>(*this);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/** \svd_module
|
|
1456
|
+
*
|
|
1457
|
+
* \return the singular value decomposition of \c *this computed by Divide & Conquer algorithm
|
|
1458
|
+
*
|
|
1459
|
+
* \sa class BDCSVD
|
|
1460
|
+
*/
|
|
1461
|
+
template <typename Derived>
|
|
1462
|
+
template <int Options>
|
|
1463
|
+
BDCSVD<typename MatrixBase<Derived>::PlainObject, Options> MatrixBase<Derived>::bdcSvd(
|
|
1464
|
+
unsigned int computationOptions) const {
|
|
1465
|
+
return BDCSVD<PlainObject, Options>(*this, computationOptions);
|
|
1362
1466
|
}
|
|
1363
1467
|
|
|
1364
|
-
}
|
|
1468
|
+
} // end namespace Eigen
|
|
1365
1469
|
|
|
1366
1470
|
#endif
|