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